diff options
| author | Laurenz <laurmaedje@gmail.com> | 2023-03-13 21:40:57 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2023-03-13 21:41:33 +0100 |
| commit | 724e9b140cc0a87208aa9c4914b1b8aeddf25c30 (patch) | |
| tree | 632984e85eb21c5a5a04c397a74725df6f7f8a28 /macros/src/node.rs | |
| parent | 880b1847bd4170ce80be5781c2163ba085cdcaff (diff) | |
Locatability and synthesis improvements
Diffstat (limited to 'macros/src/node.rs')
| -rw-r--r-- | macros/src/node.rs | 43 |
1 files changed, 35 insertions, 8 deletions
diff --git a/macros/src/node.rs b/macros/src/node.rs index 678a154d..14856074 100644 --- a/macros/src/node.rs +++ b/macros/src/node.rs @@ -34,6 +34,7 @@ struct Field { ident: Ident, ident_in: Ident, with_ident: Ident, + push_ident: Ident, set_ident: Ident, ty: syn::Type, output: syn::Type, @@ -81,6 +82,10 @@ fn prepare(stream: TokenStream, body: &syn::ItemStruct) -> Result<Node> { let required = has_attr(&mut attrs, "required") || variadic; let positional = has_attr(&mut attrs, "positional") || required; + if ident == "label" { + bail!(ident, "invalid field name"); + } + let mut field = Field { name: kebab_case(&ident), docs: documentation(&attrs), @@ -100,6 +105,7 @@ fn prepare(stream: TokenStream, body: &syn::ItemStruct) -> Result<Node> { ident: ident.clone(), ident_in: Ident::new(&format!("{}_in", ident), ident.span()), with_ident: Ident::new(&format!("with_{}", ident), ident.span()), + push_ident: Ident::new(&format!("push_{}", ident), ident.span()), set_ident: Ident::new(&format!("set_{}", ident), ident.span()), ty: field.ty.clone(), output: field.ty.clone(), @@ -162,17 +168,23 @@ fn create(node: &Node) -> TokenStream { let new = create_new_func(node); let field_methods = all.clone().map(create_field_method); let field_in_methods = settable.clone().map(create_field_in_method); - let with_fields_methods = all.map(create_with_field_method); + let with_field_methods = all.clone().map(create_with_field_method); + let push_field_methods = all.map(create_push_field_method); let field_style_methods = settable.map(create_set_field_method); // Trait implementations. - let construct = node + let node_impl = create_node_impl(node); + let construct_impl = node .capable .iter() .all(|capability| capability != "Construct") .then(|| create_construct_impl(node)); - let set = create_set_impl(node); - let node = create_node_impl(node); + let set_impl = create_set_impl(node); + let locatable_impl = node + .capable + .iter() + .any(|capability| capability == "Locatable") + .then(|| quote! { impl ::typst::model::Locatable for #ident {} }); quote! { #[doc = #docs] @@ -184,7 +196,8 @@ fn create(node: &Node) -> TokenStream { #new #(#field_methods)* #(#field_in_methods)* - #(#with_fields_methods)* + #(#with_field_methods)* + #(#push_field_methods)* #(#field_style_methods)* /// The node's span. @@ -193,9 +206,10 @@ fn create(node: &Node) -> TokenStream { } } - #node - #construct - #set + #node_impl + #construct_impl + #set_impl + #locatable_impl impl From<#ident> for ::typst::eval::Value { fn from(value: #ident) -> Self { @@ -232,6 +246,7 @@ fn create_field_method(field: &Field) -> TokenStream { if field.inherent() || field.synthesized { quote! { #[doc = #docs] + #[track_caller] #vis fn #ident(&self) -> #output { self.0.expect_field(#name) } @@ -293,6 +308,18 @@ fn create_with_field_method(field: &Field) -> TokenStream { } } +/// Create a set-style method for a field. +fn create_push_field_method(field: &Field) -> TokenStream { + let Field { vis, ident, push_ident, name, ty, .. } = field; + let doc = format!("Push the [`{}`](Self::{}) field.", name, ident); + quote! { + #[doc = #doc] + #vis fn #push_ident(&mut self, #ident: #ty) { + self.0.push_field(#name, #ident); + } + } +} + /// Create a setter method for a field. fn create_set_field_method(field: &Field) -> TokenStream { let Field { vis, ident, set_ident, name, ty, .. } = field; |
