Skip to content

Commit 81dd353

Browse files
committed
chore: add Node macro
1 parent eb1659f commit 81dd353

File tree

12 files changed

+303
-38
lines changed

12 files changed

+303
-38
lines changed

shared-lib/flowy-ast/src/ast.rs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@
44

55
use crate::event_attrs::EventEnumAttrs;
66
use crate::node_attrs::NodeStructAttrs;
7-
use crate::{is_recognizable_field, pb_attrs, ty_ext::*, ASTResult, PBAttrsContainer, PBStructAttrs};
7+
use crate::{is_recognizable_field, pb_attrs, ty_ext::*, ASTResult, PBAttrsContainer, PBStructAttrs, NODE_TYPE};
8+
use proc_macro2::Ident;
9+
use syn::Meta::NameValue;
810
use syn::{self, punctuated::Punctuated};
911

1012
pub struct ASTContainer<'a> {
1113
/// The struct or enum name (without generics).
1214
pub ident: syn::Ident,
15+
16+
pub node_type: Option<String>,
1317
/// Attributes on the structure.
14-
pub attrs: PBAttrsContainer,
18+
pub pb_attrs: PBAttrsContainer,
1519
/// The contents of the struct or enum.
1620
pub data: ASTData<'a>,
1721
}
@@ -40,7 +44,13 @@ impl<'a> ASTContainer<'a> {
4044
};
4145

4246
let ident = ast.ident.clone();
43-
let item = ASTContainer { ident, attrs, data };
47+
let node_type = get_node_type(ast_result, &ident, &ast.attrs);
48+
let item = ASTContainer {
49+
ident,
50+
pb_attrs: attrs,
51+
node_type,
52+
data,
53+
};
4454
Some(item)
4555
}
4656
}
@@ -182,7 +192,6 @@ impl<'a> ASTField<'a> {
182192
}
183193
}
184194

185-
#[allow(dead_code)]
186195
pub fn name(&self) -> Option<syn::Ident> {
187196
if let syn::Member::Named(ident) = &self.member {
188197
Some(ident.clone())
@@ -249,3 +258,21 @@ fn fields_from_ast<'a>(cx: &ASTResult, fields: &'a Punctuated<syn::Field, Token!
249258
})
250259
.collect()
251260
}
261+
262+
fn get_node_type(ast_result: &ASTResult, struct_name: &Ident, attrs: &[syn::Attribute]) -> Option<String> {
263+
let mut node_type = None;
264+
attrs
265+
.iter()
266+
.filter(|attr| attr.path.segments.iter().any(|s| s.ident == NODE_TYPE))
267+
.for_each(|attr| {
268+
if let Ok(NameValue(named_value)) = attr.parse_meta() {
269+
if node_type.is_some() {
270+
ast_result.error_spanned_by(struct_name, "Duplicate node type definition");
271+
}
272+
if let syn::Lit::Str(s) = named_value.lit {
273+
node_type = Some(s.value());
274+
}
275+
}
276+
});
277+
node_type
278+
}

shared-lib/flowy-ast/src/node_attrs.rs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
use crate::{get_node_meta_items, get_pb_meta_items, parse_lit_into_expr_path, symbol::*, ASTAttr, ASTResult};
2-
use proc_macro2::{Group, Span, TokenStream, TokenTree};
2+
use proc_macro2::{Group, Ident, Span, TokenStream, TokenTree};
33
use quote::ToTokens;
44
use syn::{
55
self,
66
parse::{self, Parse},
7+
LitStr,
78
Meta::{List, NameValue, Path},
89
NestedMeta::{Lit, Meta},
910
};
1011

1112
pub struct NodeStructAttrs {
13+
pub rename: Option<LitStr>,
14+
pub is_children: bool,
1215
node_index: Option<syn::LitInt>,
1316
get_node_value_with: Option<syn::ExprPath>,
1417
set_node_value_with: Option<syn::ExprPath>,
@@ -18,14 +21,11 @@ impl NodeStructAttrs {
1821
/// Extract out the `#[node(...)]` attributes from a struct field.
1922
pub fn from_ast(ast_result: &ASTResult, index: usize, field: &syn::Field) -> Self {
2023
let mut node_index = ASTAttr::none(ast_result, NODE_INDEX);
24+
let mut rename = ASTAttr::none(ast_result, NODE_RENAME);
25+
let mut is_children = ASTAttr::none(ast_result, NODE_CHILDREN);
2126
let mut get_node_value_with = ASTAttr::none(ast_result, GET_NODE_VALUE_WITH);
2227
let mut set_node_value_with = ASTAttr::none(ast_result, SET_NODE_VALUE_WITH);
2328

24-
let ident = match &field.ident {
25-
Some(ident) => ident.to_string(),
26-
None => index.to_string(),
27-
};
28-
2929
for meta_item in field
3030
.attrs
3131
.iter()
@@ -40,6 +40,18 @@ impl NodeStructAttrs {
4040
}
4141
}
4242

43+
// Parse '#[node(children)]'
44+
Meta(Path(path)) if path == NODE_CHILDREN => {
45+
eprintln!("😄 {:?}", path);
46+
is_children.set(path, true);
47+
}
48+
49+
// Parse '#[node(rename = x)]'
50+
Meta(NameValue(m)) if m.path == NODE_RENAME => {
51+
if let syn::Lit::Str(lit) = &m.lit {
52+
rename.set(&m.path, lit.clone());
53+
}
54+
}
4355
// Parse `#[node(get_node_value_with = "...")]`
4456
Meta(NameValue(m)) if m.path == GET_NODE_VALUE_WITH => {
4557
if let Ok(path) = parse_lit_into_expr_path(ast_result, GET_NODE_VALUE_WITH, &m.lit) {
@@ -66,7 +78,9 @@ impl NodeStructAttrs {
6678
}
6779

6880
NodeStructAttrs {
81+
rename: rename.get(),
6982
node_index: node_index.get(),
83+
is_children: is_children.get().unwrap_or(false),
7084
get_node_value_with: get_node_value_with.get(),
7185
set_node_value_with: set_node_value_with.get(),
7286
}

shared-lib/flowy-ast/src/pb_attrs.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ impl<'c, T> ASTAttr<'c, T> {
114114
}
115115
}
116116

117-
fn set_if_none(&mut self, value: T) {
117+
pub(crate) fn set_if_none(&mut self, value: T) {
118118
if self.value.is_none() {
119119
self.value = Some(value);
120120
}
@@ -260,7 +260,7 @@ pub enum Default {
260260
}
261261

262262
pub fn is_recognizable_attribute(attr: &syn::Attribute) -> bool {
263-
attr.path == PB_ATTRS || attr.path == EVENT || attr.path == NODE_ATTRS
263+
attr.path == PB_ATTRS || attr.path == EVENT || attr.path == NODE_ATTRS || attr.path == NODES_ATTRS
264264
}
265265

266266
pub fn get_pb_meta_items(cx: &ASTResult, attr: &syn::Attribute) -> Result<Vec<syn::NestedMeta>, ()> {
@@ -286,24 +286,22 @@ pub fn get_pb_meta_items(cx: &ASTResult, attr: &syn::Attribute) -> Result<Vec<sy
286286

287287
pub fn get_node_meta_items(cx: &ASTResult, attr: &syn::Attribute) -> Result<Vec<syn::NestedMeta>, ()> {
288288
// Only handle the attribute that we have defined
289-
if attr.path != NODE_ATTRS {
289+
if attr.path != NODE_ATTRS && attr.path != NODES_ATTRS {
290290
return Ok(vec![]);
291291
}
292292

293293
// http://strymon.systems.ethz.ch/typename/syn/enum.Meta.html
294294
match attr.parse_meta() {
295295
Ok(List(meta)) => Ok(meta.nested.into_iter().collect()),
296-
Ok(other) => {
297-
cx.error_spanned_by(other, "expected #[node(...)]");
298-
Err(())
299-
}
296+
Ok(_) => Ok(vec![]),
300297
Err(err) => {
301298
cx.error_spanned_by(attr, "attribute must be str, e.g. #[node(xx = \"xxx\")]");
302299
cx.syn_error(err);
303300
Err(())
304301
}
305302
}
306303
}
304+
307305
pub fn get_event_meta_items(cx: &ASTResult, attr: &syn::Attribute) -> Result<Vec<syn::NestedMeta>, ()> {
308306
// Only handle the attribute that we have defined
309307
if attr.path != EVENT {

shared-lib/flowy-ast/src/symbol.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,16 @@ pub const EVENT_ERR: Symbol = Symbol("event_err");
3434

3535
// Node
3636
pub const NODE_ATTRS: Symbol = Symbol("node");
37+
pub const NODES_ATTRS: Symbol = Symbol("nodes");
38+
pub const NODE_TYPE: Symbol = Symbol("node_type");
39+
pub const NODE_INDEX: Symbol = Symbol("index");
40+
pub const NODE_RENAME: Symbol = Symbol("rename");
41+
pub const NODE_CHILDREN: Symbol = Symbol("children");
3742
pub const SKIP_NODE_ATTRS: Symbol = Symbol("skip_node_attribute");
3843
pub const GET_NODE_VALUE_WITH: Symbol = Symbol("get_value_with");
3944
pub const SET_NODE_VALUE_WITH: Symbol = Symbol("set_value_with");
40-
//#[node(index = "1")]
41-
pub const NODE_INDEX: Symbol = Symbol("index");
45+
pub const GET_VEC_ELEMENT_WITH: Symbol = Symbol("get_element_with");
46+
pub const GET_MUT_VEC_ELEMENT_WITH: Symbol = Symbol("get_mut_element_with");
4247

4348
impl PartialEq<Symbol> for Ident {
4449
fn eq(&self, word: &Symbol) -> bool {

shared-lib/flowy-derive/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub fn derive_dart_event(input: TokenStream) -> TokenStream {
3737
.into()
3838
}
3939

40-
#[proc_macro_derive(Node, attributes(node))]
40+
#[proc_macro_derive(Node, attributes(node, nodes, node_type))]
4141
pub fn derive_node(input: TokenStream) -> TokenStream {
4242
let input = parse_macro_input!(input as DeriveInput);
4343
node::expand_derive(&input).unwrap_or_else(to_compile_errors).into()
Lines changed: 125 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,134 @@
1-
use flowy_ast::{ASTContainer, ASTResult};
1+
use flowy_ast::{ASTContainer, ASTField, ASTResult};
22
use proc_macro2::TokenStream;
33

44
pub fn expand_derive(input: &syn::DeriveInput) -> Result<TokenStream, Vec<syn::Error>> {
55
let ast_result = ASTResult::new();
6-
// let cont = match ASTContainer::from_ast(&ast_result, input) {
7-
// Some(cont) => cont,
8-
// None => return Err(ast_result.check().unwrap_err()),
9-
// };
6+
let cont = match ASTContainer::from_ast(&ast_result, input) {
7+
Some(cont) => cont,
8+
None => return Err(ast_result.check().unwrap_err()),
9+
};
1010

1111
let mut token_stream: TokenStream = TokenStream::default();
12+
token_stream.extend(make_to_node_data_token_stream(&cont));
13+
14+
if let Some(get_value_token_stream) = make_get_set_value_token_steam(&cont) {
15+
token_stream.extend(get_value_token_stream);
16+
}
17+
1218
ast_result.check()?;
1319
Ok(token_stream)
1420
}
21+
22+
pub fn make_alter_children_token_stream(ast: &ASTContainer) -> TokenStream {
23+
let mut token_streams = TokenStream::default();
24+
25+
token_streams
26+
}
27+
28+
pub fn make_to_node_data_token_stream(ast: &ASTContainer) -> TokenStream {
29+
let struct_ident = &ast.ident;
30+
let mut token_streams = TokenStream::default();
31+
let node_type = ast
32+
.node_type
33+
.as_ref()
34+
.expect("Define the type of the node by using #[node_type = \"xx\" in the struct");
35+
let set_key_values = ast
36+
.data
37+
.all_fields()
38+
.filter(|field| !field.node_attrs.is_children)
39+
.flat_map(|field| {
40+
let mut field_name = field.name().expect("the name of the field should not be empty");
41+
let original_field_name = field.name().expect("the name of the field should not be empty");
42+
if let Some(rename) = &field.node_attrs.rename {
43+
field_name = format_ident!("{}", rename.value());
44+
}
45+
let field_name_str = field_name.to_string();
46+
quote! {
47+
.insert_attribute(#field_name_str, self.#original_field_name.clone())
48+
}
49+
});
50+
51+
let children_fields = ast
52+
.data
53+
.all_fields()
54+
.filter(|field| field.node_attrs.is_children)
55+
.collect::<Vec<&ASTField>>();
56+
57+
let childrens_token_streams = match children_fields.is_empty() {
58+
true => {
59+
quote! {
60+
let children = vec![];
61+
}
62+
}
63+
false => {
64+
let children_field = children_fields.first().unwrap();
65+
let original_field_name = children_field
66+
.name()
67+
.expect("the name of the field should not be empty");
68+
quote! {
69+
let children = self.#original_field_name.iter().map(|value| value.to_node_data()).collect::<Vec<NodeData>>();
70+
}
71+
}
72+
};
73+
74+
token_streams.extend(quote! {
75+
impl #struct_ident {
76+
pub fn to_node_data(&self) -> NodeData {
77+
#childrens_token_streams
78+
79+
let builder = NodeDataBuilder::new(#node_type)
80+
#(#set_key_values)*
81+
.extend_node_data(children);
82+
83+
builder.build()
84+
}
85+
}
86+
});
87+
88+
token_streams
89+
}
90+
91+
pub fn make_get_set_value_token_steam(ast: &ASTContainer) -> Option<TokenStream> {
92+
let struct_ident = &ast.ident;
93+
let mut token_streams = TokenStream::default();
94+
95+
let tree = format_ident!("tree");
96+
for field in ast.data.all_fields() {
97+
if field.node_attrs.is_children {
98+
continue;
99+
}
100+
101+
let mut field_name = field.name().expect("the name of the field should not be empty");
102+
if let Some(rename) = &field.node_attrs.rename {
103+
field_name = format_ident!("{}", rename.value());
104+
}
105+
106+
let field_name_str = field_name.to_string();
107+
let get_func_name = format_ident!("get_{}", field_name);
108+
let set_func_name = format_ident!("set_{}", field_name);
109+
let get_value_return_ty = field.ty;
110+
let set_value_input_ty = field.ty;
111+
112+
if let Some(get_value_with_fn) = field.node_attrs.get_node_value_with() {
113+
token_streams.extend(quote! {
114+
impl #struct_ident {
115+
pub fn #get_func_name(&self) -> Option<#get_value_return_ty> {
116+
#get_value_with_fn(self.#tree.clone(), &self.path, #field_name_str)
117+
}
118+
}
119+
});
120+
}
121+
122+
if let Some(set_value_with_fn) = field.node_attrs.set_node_value_with() {
123+
token_streams.extend(quote! {
124+
impl #struct_ident {
125+
pub fn #set_func_name(&self, value: #set_value_input_ty) {
126+
let _ = #set_value_with_fn(self.#tree.clone(), &self.path, #field_name_str, value);
127+
}
128+
}
129+
});
130+
}
131+
}
132+
ast.data.all_fields().for_each(|field| {});
133+
Some(token_streams)
134+
}

shared-lib/flowy-derive/src/proto_buf/deserialize.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use crate::proto_buf::util::*;
22
use flowy_ast::*;
33
use proc_macro2::{Span, TokenStream};
44

5-
pub fn make_de_token_steam(ctxt: &ASTResult, ast: &ASTContainer) -> Option<TokenStream> {
6-
let pb_ty = ast.attrs.pb_struct_type()?;
5+
pub fn make_de_token_steam(ast_result: &ASTResult, ast: &ASTContainer) -> Option<TokenStream> {
6+
let pb_ty = ast.pb_attrs.pb_struct_type()?;
77
let struct_ident = &ast.ident;
88

99
let build_take_fields = ast
@@ -15,9 +15,9 @@ pub fn make_de_token_steam(ctxt: &ASTResult, ast: &ASTContainer) -> Option<Token
1515
let member = &field.member;
1616
Some(quote! { o.#member=#struct_ident::#func(pb); })
1717
} else if field.pb_attrs.is_one_of() {
18-
token_stream_for_one_of(ctxt, field)
18+
token_stream_for_one_of(ast_result, field)
1919
} else {
20-
token_stream_for_field(ctxt, &field.member, field.ty, false)
20+
token_stream_for_field(ast_result, &field.member, field.ty, false)
2121
}
2222
});
2323

@@ -58,10 +58,10 @@ pub fn make_de_token_steam(ctxt: &ASTResult, ast: &ASTContainer) -> Option<Token
5858
// None
5959
}
6060

61-
fn token_stream_for_one_of(ctxt: &ASTResult, field: &ASTField) -> Option<TokenStream> {
61+
fn token_stream_for_one_of(ast_result: &ASTResult, field: &ASTField) -> Option<TokenStream> {
6262
let member = &field.member;
63-
let ident = get_member_ident(ctxt, member)?;
64-
let ty_info = match parse_ty(ctxt, field.ty) {
63+
let ident = get_member_ident(ast_result, member)?;
64+
let ty_info = match parse_ty(ast_result, field.ty) {
6565
Ok(ty_info) => ty_info,
6666
Err(e) => {
6767
eprintln!("token_stream_for_one_of failed: {:?} with error: {}", member, e);

shared-lib/flowy-derive/src/proto_buf/enum_serde.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use proc_macro2::TokenStream;
44
#[allow(dead_code)]
55
pub fn make_enum_token_stream(_ast_result: &ASTResult, cont: &ASTContainer) -> Option<TokenStream> {
66
let enum_ident = &cont.ident;
7-
let pb_enum = cont.attrs.pb_enum_type()?;
7+
let pb_enum = cont.pb_attrs.pb_enum_type()?;
88
let build_to_pb_enum = cont.data.all_idents().map(|i| {
99
let token_stream: TokenStream = quote! {
1010
#enum_ident::#i => crate::protobuf::#pb_enum::#i,

shared-lib/flowy-derive/src/proto_buf/serialize.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use flowy_ast::*;
44
use proc_macro2::TokenStream;
55

66
pub fn make_se_token_stream(ast_result: &ASTResult, ast: &ASTContainer) -> Option<TokenStream> {
7-
let pb_ty = ast.attrs.pb_struct_type()?;
7+
let pb_ty = ast.pb_attrs.pb_struct_type()?;
88
let struct_ident = &ast.ident;
99

1010
let build_set_pb_fields = ast

0 commit comments

Comments
 (0)