Skip to content

Commit 6e8944c

Browse files
committed
Refactor: generalize parsing module item attributes
commit-id:e3794f71
1 parent 204418c commit 6e8944c

File tree

5 files changed

+158
-77
lines changed

5 files changed

+158
-77
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
use cairo_lang_syntax::node::ast::{
2+
Attribute, FunctionWithBody, ItemEnum, ItemExternFunction, ItemExternType, ItemImpl,
3+
ItemModule, ItemStruct, ItemTrait,
4+
};
5+
use cairo_lang_syntax::node::db::SyntaxGroup;
6+
use cairo_lang_syntax::node::{SyntaxNode, TypedSyntaxNode};
7+
8+
pub trait ItemWithAttributes {
9+
fn item_attributes(&self, db: &dyn SyntaxGroup) -> Vec<Attribute>;
10+
}
11+
12+
pub trait ChildNodesWithoutAttributes {
13+
fn child_nodes_without_attributes(
14+
&self,
15+
db: &dyn SyntaxGroup,
16+
) -> impl Iterator<Item = SyntaxNode>;
17+
}
18+
19+
macro_rules! impl_child_nodes_without_attributes {
20+
($t:ty, [$($child:ident),* $(,)?]) => {
21+
impl ChildNodesWithoutAttributes for $t {
22+
fn child_nodes_without_attributes(
23+
&self,
24+
db: &dyn SyntaxGroup,
25+
) -> impl Iterator<Item = SyntaxNode> {
26+
[
27+
$(self.$child(db).as_syntax_node()),*
28+
].into_iter()
29+
}
30+
}
31+
};
32+
}
33+
34+
macro_rules! impl_item_with_attributes {
35+
($t:ty) => {
36+
impl ItemWithAttributes for $t {
37+
fn item_attributes(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
38+
self.attributes(db).elements(db)
39+
}
40+
}
41+
};
42+
}
43+
44+
impl_item_with_attributes!(ItemTrait);
45+
impl_child_nodes_without_attributes!(
46+
ItemTrait,
47+
[visibility, trait_kw, name, generic_params, body]
48+
);
49+
50+
impl_item_with_attributes!(ItemImpl);
51+
impl_child_nodes_without_attributes!(
52+
ItemImpl,
53+
[
54+
visibility,
55+
impl_kw,
56+
name,
57+
generic_params,
58+
of_kw,
59+
trait_path,
60+
body
61+
]
62+
);
63+
64+
impl_item_with_attributes!(ItemModule);
65+
impl_child_nodes_without_attributes!(ItemModule, [visibility, module_kw, name, body]);
66+
67+
impl_item_with_attributes!(FunctionWithBody);
68+
impl_child_nodes_without_attributes!(FunctionWithBody, [visibility, declaration, body]);
69+
70+
impl_item_with_attributes!(ItemExternFunction);
71+
impl_child_nodes_without_attributes!(
72+
ItemExternFunction,
73+
[visibility, extern_kw, declaration, semicolon]
74+
);
75+
76+
impl_item_with_attributes!(ItemExternType);
77+
impl_child_nodes_without_attributes!(
78+
ItemExternType,
79+
[
80+
visibility,
81+
extern_kw,
82+
type_kw,
83+
name,
84+
generic_params,
85+
semicolon
86+
]
87+
);
88+
89+
impl_item_with_attributes!(ItemStruct);
90+
impl_child_nodes_without_attributes!(
91+
ItemStruct,
92+
[
93+
visibility,
94+
struct_kw,
95+
name,
96+
generic_params,
97+
lbrace,
98+
members,
99+
rbrace
100+
]
101+
);
102+
103+
impl_item_with_attributes!(ItemEnum);
104+
impl_child_nodes_without_attributes!(
105+
ItemEnum,
106+
[
107+
visibility,
108+
enum_kw,
109+
name,
110+
generic_params,
111+
lbrace,
112+
variants,
113+
rbrace
114+
]
115+
);

scarb/src/compiler/plugin/proc_macro/v2/host/attribute/item_attribute.rs

+33-76
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
use crate::compiler::plugin::proc_macro::v2::host::attribute::child_nodes::{
2+
ChildNodesWithoutAttributes, ItemWithAttributes,
3+
};
14
use crate::compiler::plugin::proc_macro::v2::host::aux_data::{EmittedAuxData, ProcMacroAuxData};
25
use crate::compiler::plugin::proc_macro::v2::host::conversion::{
36
CallSiteLocation, into_cairo_diagnostics,
@@ -8,8 +11,8 @@ use crate::compiler::plugin::proc_macro::v2::{
811
};
912
use cairo_lang_defs::plugin::{DynGeneratedFileAuxData, PluginGeneratedFile, PluginResult};
1013
use cairo_lang_macro::{AllocationContext, TokenStream};
14+
use cairo_lang_syntax::node::ast;
1115
use cairo_lang_syntax::node::db::SyntaxGroup;
12-
use cairo_lang_syntax::node::{TypedSyntaxNode, ast};
1316
use smol_str::SmolStr;
1417

1518
impl ProcMacroHostPlugin {
@@ -24,88 +27,29 @@ impl ProcMacroHostPlugin {
2427
) -> (AttrExpansionFound, TokenStream) {
2528
let mut token_stream_builder = TokenStreamBuilder::new(db);
2629
let input = match item_ast.clone() {
27-
ast::ModuleItem::Trait(trait_ast) => {
28-
let attrs = trait_ast.attributes(db).elements(db);
29-
let expansion = self.parse_attrs(db, &mut token_stream_builder, attrs, ctx);
30-
token_stream_builder.add_node(trait_ast.visibility(db).as_syntax_node());
31-
token_stream_builder.add_node(trait_ast.trait_kw(db).as_syntax_node());
32-
token_stream_builder.add_node(trait_ast.name(db).as_syntax_node());
33-
token_stream_builder.add_node(trait_ast.generic_params(db).as_syntax_node());
34-
token_stream_builder.add_node(trait_ast.body(db).as_syntax_node());
35-
expansion
30+
ast::ModuleItem::Trait(ast) => {
31+
parse_item(&ast, db, self, &mut token_stream_builder, ctx)
3632
}
37-
ast::ModuleItem::Impl(impl_ast) => {
38-
let attrs = impl_ast.attributes(db).elements(db);
39-
let expansion = self.parse_attrs(db, &mut token_stream_builder, attrs, ctx);
40-
token_stream_builder.add_node(impl_ast.visibility(db).as_syntax_node());
41-
token_stream_builder.add_node(impl_ast.impl_kw(db).as_syntax_node());
42-
token_stream_builder.add_node(impl_ast.name(db).as_syntax_node());
43-
token_stream_builder.add_node(impl_ast.generic_params(db).as_syntax_node());
44-
token_stream_builder.add_node(impl_ast.of_kw(db).as_syntax_node());
45-
token_stream_builder.add_node(impl_ast.trait_path(db).as_syntax_node());
46-
token_stream_builder.add_node(impl_ast.body(db).as_syntax_node());
47-
expansion
33+
ast::ModuleItem::Impl(ast) => {
34+
parse_item(&ast, db, self, &mut token_stream_builder, ctx)
4835
}
49-
ast::ModuleItem::Module(module_ast) => {
50-
let attrs = module_ast.attributes(db).elements(db);
51-
let expansion = self.parse_attrs(db, &mut token_stream_builder, attrs, ctx);
52-
token_stream_builder.add_node(module_ast.visibility(db).as_syntax_node());
53-
token_stream_builder.add_node(module_ast.module_kw(db).as_syntax_node());
54-
token_stream_builder.add_node(module_ast.name(db).as_syntax_node());
55-
token_stream_builder.add_node(module_ast.body(db).as_syntax_node());
56-
expansion
36+
ast::ModuleItem::Module(ast) => {
37+
parse_item(&ast, db, self, &mut token_stream_builder, ctx)
5738
}
58-
ast::ModuleItem::FreeFunction(free_func_ast) => {
59-
let attrs = free_func_ast.attributes(db).elements(db);
60-
let expansion = self.parse_attrs(db, &mut token_stream_builder, attrs, ctx);
61-
token_stream_builder.add_node(free_func_ast.visibility(db).as_syntax_node());
62-
token_stream_builder.add_node(free_func_ast.declaration(db).as_syntax_node());
63-
token_stream_builder.add_node(free_func_ast.body(db).as_syntax_node());
64-
expansion
39+
ast::ModuleItem::FreeFunction(ast) => {
40+
parse_item(&ast, db, self, &mut token_stream_builder, ctx)
6541
}
66-
ast::ModuleItem::ExternFunction(extern_func_ast) => {
67-
let attrs = extern_func_ast.attributes(db).elements(db);
68-
let expansion = self.parse_attrs(db, &mut token_stream_builder, attrs, ctx);
69-
token_stream_builder.add_node(extern_func_ast.visibility(db).as_syntax_node());
70-
token_stream_builder.add_node(extern_func_ast.extern_kw(db).as_syntax_node());
71-
token_stream_builder.add_node(extern_func_ast.declaration(db).as_syntax_node());
72-
token_stream_builder.add_node(extern_func_ast.semicolon(db).as_syntax_node());
73-
expansion
42+
ast::ModuleItem::ExternFunction(ast) => {
43+
parse_item(&ast, db, self, &mut token_stream_builder, ctx)
7444
}
75-
ast::ModuleItem::ExternType(extern_type_ast) => {
76-
let attrs = extern_type_ast.attributes(db).elements(db);
77-
let expansion = self.parse_attrs(db, &mut token_stream_builder, attrs, ctx);
78-
token_stream_builder.add_node(extern_type_ast.visibility(db).as_syntax_node());
79-
token_stream_builder.add_node(extern_type_ast.extern_kw(db).as_syntax_node());
80-
token_stream_builder.add_node(extern_type_ast.type_kw(db).as_syntax_node());
81-
token_stream_builder.add_node(extern_type_ast.name(db).as_syntax_node());
82-
token_stream_builder.add_node(extern_type_ast.generic_params(db).as_syntax_node());
83-
token_stream_builder.add_node(extern_type_ast.semicolon(db).as_syntax_node());
84-
expansion
45+
ast::ModuleItem::ExternType(ast) => {
46+
parse_item(&ast, db, self, &mut token_stream_builder, ctx)
8547
}
86-
ast::ModuleItem::Struct(struct_ast) => {
87-
let attrs = struct_ast.attributes(db).elements(db);
88-
let expansion = self.parse_attrs(db, &mut token_stream_builder, attrs, ctx);
89-
token_stream_builder.add_node(struct_ast.visibility(db).as_syntax_node());
90-
token_stream_builder.add_node(struct_ast.struct_kw(db).as_syntax_node());
91-
token_stream_builder.add_node(struct_ast.name(db).as_syntax_node());
92-
token_stream_builder.add_node(struct_ast.generic_params(db).as_syntax_node());
93-
token_stream_builder.add_node(struct_ast.lbrace(db).as_syntax_node());
94-
token_stream_builder.add_node(struct_ast.members(db).as_syntax_node());
95-
token_stream_builder.add_node(struct_ast.rbrace(db).as_syntax_node());
96-
expansion
48+
ast::ModuleItem::Struct(ast) => {
49+
parse_item(&ast, db, self, &mut token_stream_builder, ctx)
9750
}
98-
ast::ModuleItem::Enum(enum_ast) => {
99-
let attrs = enum_ast.attributes(db).elements(db);
100-
let expansion = self.parse_attrs(db, &mut token_stream_builder, attrs, ctx);
101-
token_stream_builder.add_node(enum_ast.visibility(db).as_syntax_node());
102-
token_stream_builder.add_node(enum_ast.enum_kw(db).as_syntax_node());
103-
token_stream_builder.add_node(enum_ast.name(db).as_syntax_node());
104-
token_stream_builder.add_node(enum_ast.generic_params(db).as_syntax_node());
105-
token_stream_builder.add_node(enum_ast.lbrace(db).as_syntax_node());
106-
token_stream_builder.add_node(enum_ast.variants(db).as_syntax_node());
107-
token_stream_builder.add_node(enum_ast.rbrace(db).as_syntax_node());
108-
expansion
51+
ast::ModuleItem::Enum(ast) => {
52+
parse_item(&ast, db, self, &mut token_stream_builder, ctx)
10953
}
11054
_ => AttrExpansionFound::None,
11155
};
@@ -189,6 +133,19 @@ impl ProcMacroHostPlugin {
189133
}
190134
}
191135

136+
fn parse_item<T: ItemWithAttributes + ChildNodesWithoutAttributes>(
137+
ast: &T,
138+
db: &dyn SyntaxGroup,
139+
host: &ProcMacroHostPlugin,
140+
token_stream_builder: &mut TokenStreamBuilder<'_>,
141+
ctx: &AllocationContext,
142+
) -> AttrExpansionFound {
143+
let attrs = ast.item_attributes(db);
144+
let expansion = host.parse_attrs(db, token_stream_builder, attrs, ctx);
145+
token_stream_builder.extend(ast.child_nodes_without_attributes(db));
146+
expansion
147+
}
148+
192149
pub enum AttrExpansionFound {
193150
Some(AttrExpansionArgs),
194151
Last(AttrExpansionArgs),

scarb/src/compiler/plugin/proc_macro/v2/host/attribute/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod child_nodes;
12
mod inner_attribute;
23
mod item_attribute;
34
mod parse_attributes;

scarb/src/compiler/plugin/proc_macro/v2/host/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ impl ProcMacroHostPlugin {
9999
})
100100
}
101101

102-
fn find_expansion(&self, query: &ExpansionQuery) -> Option<ProcMacroId> {
102+
pub(crate) fn find_expansion(&self, query: &ExpansionQuery) -> Option<ProcMacroId> {
103103
let instance = self.find_instance_with_expansion(query)?;
104104
let expansion = instance.find_expansion(query)?;
105105
Some(ProcMacroId::new(instance.package_id(), expansion.clone()))

scarb/src/compiler/plugin/proc_macro/v2/types.rs

+8
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@ impl<'a> TokenStreamBuilder<'a> {
5858
}
5959
}
6060

61+
impl Extend<SyntaxNode> for TokenStreamBuilder<'_> {
62+
fn extend<T: IntoIterator<Item = SyntaxNode>>(&mut self, iter: T) {
63+
for node in iter {
64+
self.add_node(node);
65+
}
66+
}
67+
}
68+
6169
fn whitespace_prefix_len(s: &str) -> u32 {
6270
s.chars().take_while(|c| c.is_whitespace()).count() as u32
6371
}

0 commit comments

Comments
 (0)