diff options
| author | Laurenz <laurmaedje@gmail.com> | 2023-11-23 16:25:49 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2023-11-24 12:30:02 +0100 |
| commit | 7eebafa7837ec173a7b2064ae60fd45b5413d17c (patch) | |
| tree | b63b302b6d7747bcbb28571713745b9ca1aa83a4 /crates/typst-macros/src | |
| parent | 76e173b78b511b506b928c27ac360f75fa455747 (diff) | |
Merge `typst` and `typst-library`
Diffstat (limited to 'crates/typst-macros/src')
| -rw-r--r-- | crates/typst-macros/src/cast.rs | 59 | ||||
| -rw-r--r-- | crates/typst-macros/src/category.rs | 57 | ||||
| -rw-r--r-- | crates/typst-macros/src/elem.rs | 234 | ||||
| -rw-r--r-- | crates/typst-macros/src/func.rs | 50 | ||||
| -rw-r--r-- | crates/typst-macros/src/lib.rs | 23 | ||||
| -rw-r--r-- | crates/typst-macros/src/scope.rs | 18 | ||||
| -rw-r--r-- | crates/typst-macros/src/symbols.rs | 11 | ||||
| -rw-r--r-- | crates/typst-macros/src/ty.rs | 30 | ||||
| -rw-r--r-- | crates/typst-macros/src/util.rs | 39 |
9 files changed, 302 insertions, 219 deletions
diff --git a/crates/typst-macros/src/cast.rs b/crates/typst-macros/src/cast.rs index b83dbedd..f2115aa9 100644 --- a/crates/typst-macros/src/cast.rs +++ b/crates/typst-macros/src/cast.rs @@ -1,4 +1,11 @@ -use super::*; +use heck::ToKebabCase; +use proc_macro2::TokenStream; +use quote::quote; +use syn::parse::{Parse, ParseStream}; +use syn::punctuated::Punctuated; +use syn::{DeriveInput, Ident, Result, Token}; + +use crate::util::{documentation, foundations}; /// Expand the `#[derive(Cast)]` macro. pub fn derive_cast(item: DeriveInput) -> Result<TokenStream> { @@ -43,9 +50,9 @@ pub fn derive_cast(item: DeriveInput) -> Result<TokenStream> { }); Ok(quote! { - ::typst::eval::cast! { + #foundations::cast! { #ty, - self => ::typst::eval::IntoValue::into_value(match self { + self => #foundations::IntoValue::into_value(match self { #(#variants_to_strs),* }), #(#strs_to_variants),* @@ -62,8 +69,6 @@ struct Variant { /// Expand the `cast!` macro. pub fn cast(stream: TokenStream) -> Result<TokenStream> { - let eval = quote! { ::typst::eval }; - let input: CastInput = syn::parse2(stream)?; let ty = &input.ty; let castable_body = create_castable_body(&input); @@ -74,16 +79,16 @@ pub fn cast(stream: TokenStream) -> Result<TokenStream> { let reflect = (!input.from_value.is_empty() || input.dynamic).then(|| { quote! { - impl #eval::Reflect for #ty { - fn input() -> #eval::CastInfo { + impl #foundations::Reflect for #ty { + fn input() -> #foundations::CastInfo { #input_body } - fn output() -> #eval::CastInfo { + fn output() -> #foundations::CastInfo { #output_body } - fn castable(value: &#eval::Value) -> bool { + fn castable(value: &#foundations::Value) -> bool { #castable_body } } @@ -92,8 +97,8 @@ pub fn cast(stream: TokenStream) -> Result<TokenStream> { let into_value = (input.into_value.is_some() || input.dynamic).then(|| { quote! { - impl #eval::IntoValue for #ty { - fn into_value(self) -> #eval::Value { + impl #foundations::IntoValue for #ty { + fn into_value(self) -> #foundations::Value { #into_value_body } } @@ -102,8 +107,8 @@ pub fn cast(stream: TokenStream) -> Result<TokenStream> { let from_value = (!input.from_value.is_empty() || input.dynamic).then(|| { quote! { - impl #eval::FromValue for #ty { - fn from_value(value: #eval::Value) -> ::typst::diag::StrResult<Self> { + impl #foundations::FromValue for #ty { + fn from_value(value: #foundations::Value) -> ::typst::diag::StrResult<Self> { #from_value_body } } @@ -196,7 +201,7 @@ fn create_castable_body(input: &CastInput) -> TokenStream { } Pattern::Ty(_, ty) => { casts.push(quote! { - if <#ty as ::typst::eval::Reflect>::castable(value) { + if <#ty as #foundations::Reflect>::castable(value) { return true; } }); @@ -206,7 +211,7 @@ fn create_castable_body(input: &CastInput) -> TokenStream { let dynamic_check = input.dynamic.then(|| { quote! { - if let ::typst::eval::Value::Dyn(dynamic) = &value { + if let #foundations::Value::Dyn(dynamic) = &value { if dynamic.is::<Self>() { return true; } @@ -216,7 +221,7 @@ fn create_castable_body(input: &CastInput) -> TokenStream { let str_check = (!strings.is_empty()).then(|| { quote! { - if let ::typst::eval::Value::Str(string) = &value { + if let #foundations::Value::Str(string) = &value { match string.as_str() { #(#strings,)* _ => {} @@ -241,21 +246,21 @@ fn create_input_body(input: &CastInput) -> TokenStream { infos.push(match &cast.pattern { Pattern::Str(lit) => { quote! { - ::typst::eval::CastInfo::Value( - ::typst::eval::IntoValue::into_value(#lit), + #foundations::CastInfo::Value( + #foundations::IntoValue::into_value(#lit), #docs, ) } } Pattern::Ty(_, ty) => { - quote! { <#ty as ::typst::eval::Reflect>::input() } + quote! { <#ty as #foundations::Reflect>::input() } } }); } if input.dynamic { infos.push(quote! { - ::typst::eval::CastInfo::Type(::typst::eval::Type::of::<Self>()) + #foundations::CastInfo::Type(#foundations::Type::of::<Self>()) }); } @@ -266,7 +271,7 @@ fn create_input_body(input: &CastInput) -> TokenStream { fn create_output_body(input: &CastInput) -> TokenStream { if input.dynamic { - quote! { ::typst::eval::CastInfo::Type(::typst::eval::Type::of::<Self>()) } + quote! { #foundations::CastInfo::Type(#foundations::Type::of::<Self>()) } } else { quote! { Self::input() } } @@ -276,7 +281,7 @@ fn create_into_value_body(input: &CastInput) -> TokenStream { if let Some(expr) = &input.into_value { quote! { #expr } } else { - quote! { ::typst::eval::Value::dynamic(self) } + quote! { #foundations::Value::dynamic(self) } } } @@ -292,8 +297,8 @@ fn create_from_value_body(input: &CastInput) -> TokenStream { } Pattern::Ty(binding, ty) => { cast_checks.push(quote! { - if <#ty as ::typst::eval::Reflect>::castable(&value) { - let #binding = <#ty as ::typst::eval::FromValue>::from_value(value)?; + if <#ty as #foundations::Reflect>::castable(&value) { + let #binding = <#ty as #foundations::FromValue>::from_value(value)?; return Ok(#expr); } }); @@ -303,7 +308,7 @@ fn create_from_value_body(input: &CastInput) -> TokenStream { let dynamic_check = input.dynamic.then(|| { quote! { - if let ::typst::eval::Value::Dyn(dynamic) = &value { + if let #foundations::Value::Dyn(dynamic) = &value { if let Some(concrete) = dynamic.downcast::<Self>() { return Ok(concrete.clone()); } @@ -313,7 +318,7 @@ fn create_from_value_body(input: &CastInput) -> TokenStream { let str_check = (!string_arms.is_empty()).then(|| { quote! { - if let ::typst::eval::Value::Str(string) = &value { + if let #foundations::Value::Str(string) = &value { match string.as_str() { #(#string_arms,)* _ => {} @@ -326,6 +331,6 @@ fn create_from_value_body(input: &CastInput) -> TokenStream { #dynamic_check #str_check #(#cast_checks)* - Err(<Self as ::typst::eval::Reflect>::error(&value)) + Err(<Self as #foundations::Reflect>::error(&value)) } } diff --git a/crates/typst-macros/src/category.rs b/crates/typst-macros/src/category.rs new file mode 100644 index 00000000..399a0510 --- /dev/null +++ b/crates/typst-macros/src/category.rs @@ -0,0 +1,57 @@ +use heck::{ToKebabCase, ToTitleCase}; +use proc_macro2::TokenStream; +use quote::quote; +use syn::parse::{Parse, ParseStream}; +use syn::{Attribute, Ident, Result, Token, Type, Visibility}; + +use crate::util::{documentation, foundations}; + +/// Expand the `#[category]` macro. +pub fn category(_: TokenStream, item: syn::Item) -> Result<TokenStream> { + let syn::Item::Verbatim(stream) = item else { + bail!(item, "expected bare static"); + }; + + let BareStatic { attrs, vis, ident, ty, .. } = syn::parse2(stream)?; + + let name = ident.to_string().to_kebab_case(); + let title = name.to_title_case(); + let docs = documentation(&attrs); + + Ok(quote! { + #(#attrs)* + #vis static #ident: #ty = { + static DATA: #foundations::CategoryData = #foundations::CategoryData { + name: #name, + title: #title, + docs: #docs, + }; + #foundations::Category::from_data(&DATA) + }; + }) +} + +/// Parse a bare `pub static CATEGORY: Category;` item. +pub struct BareStatic { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub static_token: Token![static], + pub ident: Ident, + pub colon_token: Token![:], + pub ty: Type, + pub semi_token: Token![;], +} + +impl Parse for BareStatic { + fn parse(input: ParseStream) -> Result<Self> { + Ok(Self { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + static_token: input.parse()?, + ident: input.parse()?, + colon_token: input.parse()?, + ty: input.parse()?, + semi_token: input.parse()?, + }) + } +} diff --git a/crates/typst-macros/src/elem.rs b/crates/typst-macros/src/elem.rs index 2de0adf2..9791427b 100644 --- a/crates/typst-macros/src/elem.rs +++ b/crates/typst-macros/src/elem.rs @@ -1,4 +1,15 @@ -use super::*; +use heck::{ToKebabCase, ToShoutySnakeCase, ToUpperCamelCase}; +use proc_macro2::TokenStream; +use quote::quote; +use syn::parse::{Parse, ParseStream}; +use syn::punctuated::Punctuated; +use syn::{parse_quote, Ident, Result, Token}; + +use crate::util::{ + determine_name_and_title, documentation, foundations, has_attr, kw, parse_attr, + parse_flag, parse_string, parse_string_array, quote_option, validate_attrs, + BlockWithReturn, +}; /// Expand the `#[elem]` macro. pub fn elem(stream: TokenStream, body: syn::ItemStruct) -> Result<TokenStream> { @@ -136,7 +147,6 @@ struct Field { synthesized: bool, borrowed: bool, ghost: bool, - forced_variant: Option<usize>, parse: Option<BlockWithReturn>, default: Option<syn::Expr>, } @@ -226,10 +236,6 @@ fn parse_field(field: &syn::Field) -> Result<Field> { docs: documentation(&attrs), internal: has_attr(&mut attrs, "internal"), external: has_attr(&mut attrs, "external"), - forced_variant: parse_attr::<syn::LitInt>(&mut attrs, "variant")? - .flatten() - .map(|lit| lit.base10_parse()) - .transpose()?, positional, required, variadic, @@ -262,12 +268,12 @@ fn parse_field(field: &syn::Field) -> Result<Field> { if field.resolve { let output = &field.output; - field.output = parse_quote! { <#output as ::typst::model::Resolve>::Output }; + field.output = parse_quote! { <#output as #foundations::Resolve>::Output }; } if field.fold { let output = &field.output; - field.output = parse_quote! { <#output as ::typst::model::Fold>::Output }; + field.output = parse_quote! { <#output as #foundations::Fold>::Output }; } validate_attrs(&attrs)?; @@ -317,8 +323,8 @@ fn create(element: &Elem) -> Result<TokenStream> { let label_and_location = element.unless_capability("Unlabellable", || { quote! { - location: Option<::typst::model::Location>, - label: Option<::typst::model::Label>, + location: Option<::typst::introspection::Location>, + label: Option<#foundations::Label>, prepared: bool, } }); @@ -330,7 +336,7 @@ fn create(element: &Elem) -> Result<TokenStream> { #vis struct #ident { span: ::typst::syntax::Span, #label_and_location - guards: ::std::vec::Vec<::typst::model::Guard>, + guards: ::std::vec::Vec<#foundations::Guard>, #(#fields,)* } @@ -353,9 +359,9 @@ fn create(element: &Elem) -> Result<TokenStream> { #partial_eq_impl #repr_impl - impl ::typst::eval::IntoValue for #ident { - fn into_value(self) -> ::typst::eval::Value { - ::typst::eval::Value::Content(::typst::model::Content::new(self)) + impl #foundations::IntoValue for #ident { + fn into_value(self) -> #foundations::Value { + #foundations::Value::Content(#foundations::Content::new(self)) } } }) @@ -382,12 +388,9 @@ fn create_field(field: &Field) -> TokenStream { /// Creates the element's enum for field identifiers. fn create_fields_enum(element: &Elem) -> TokenStream { - let model = quote! { ::typst::model }; let Elem { ident, enum_ident, .. } = element; - let mut fields = element.real_fields().collect::<Vec<_>>(); - fields.sort_by_key(|field| field.forced_variant.unwrap_or(usize::MAX)); - + let fields = element.real_fields().collect::<Vec<_>>(); let field_names = fields.iter().map(|Field { name, .. }| name).collect::<Vec<_>>(); let field_consts = fields .iter() @@ -399,20 +402,14 @@ fn create_fields_enum(element: &Elem) -> TokenStream { .map(|Field { enum_ident, .. }| enum_ident) .collect::<Vec<_>>(); - let definitions = - fields.iter().map(|Field { forced_variant, enum_ident, .. }| { - if let Some(variant) = forced_variant { - let variant = proc_macro2::Literal::u8_unsuffixed(*variant as _); - quote! { #enum_ident = #variant } - } else { - quote! { #enum_ident } - } - }); + let definitions = fields.iter().map(|Field { enum_ident, .. }| { + quote! { #enum_ident } + }); quote! { // To hide the private type const _: () = { - impl #model::ElementFields for #ident { + impl #foundations::ElementFields for #ident { type Fields = #enum_ident; } @@ -578,16 +575,15 @@ fn create_push_field_method(field: &Field) -> TokenStream { /// Create a setter method for a field. fn create_set_field_method(element: &Elem, field: &Field) -> TokenStream { - let model = quote! { ::typst::model }; let elem = &element.ident; let Field { vis, ident, set_ident, enum_ident, ty, name, .. } = field; let doc = format!("Create a style property for the `{}` field.", name); quote! { #[doc = #doc] - #vis fn #set_ident(#ident: #ty) -> ::typst::model::Style { - ::typst::model::Style::Property(::typst::model::Property::new( - <Self as ::typst::model::NativeElement>::elem(), - <#elem as #model::ElementFields>::Fields::#enum_ident as u8, + #vis fn #set_ident(#ident: #ty) -> #foundations::Style { + #foundations::Style::Property(#foundations::Property::new( + <Self as #foundations::NativeElement>::elem(), + <#elem as #foundations::ElementFields>::Fields::#enum_ident as u8, #ident, )) } @@ -608,7 +604,7 @@ fn create_field_in_method(element: &Elem, field: &Field) -> TokenStream { quote! { #[doc = #doc] - #vis fn #ident_in(styles: ::typst::model::StyleChain) -> #output { + #vis fn #ident_in(styles: #foundations::StyleChain) -> #output { #access } } @@ -646,7 +642,7 @@ fn create_field_method(element: &Elem, field: &Field) -> TokenStream { quote! { #[doc = #docs] - #vis fn #ident<'a>(&'a self, styles: ::typst::model::StyleChain<'a>) -> &'a #output { + #vis fn #ident<'a>(&'a self, styles: #foundations::StyleChain<'a>) -> &'a #output { #access } } @@ -655,7 +651,7 @@ fn create_field_method(element: &Elem, field: &Field) -> TokenStream { quote! { #[doc = #docs] - #vis fn #ident(&self, styles: ::typst::model::StyleChain) -> #output { + #vis fn #ident(&self, styles: #foundations::StyleChain) -> #output { #access } } @@ -668,7 +664,6 @@ fn create_style_chain_access( field: &Field, inherent: TokenStream, ) -> TokenStream { - let model = quote! { ::typst::model }; let elem = &element.ident; let Field { ty, default, enum_ident, .. } = field; @@ -693,8 +688,8 @@ fn create_style_chain_access( quote! { #init styles.#getter::<#ty>( - <Self as ::typst::model::NativeElement>::elem(), - <#elem as #model::ElementFields>::Fields::#enum_ident as u8, + <Self as #foundations::NativeElement>::elem(), + <#elem as #foundations::ElementFields>::Fields::#enum_ident as u8, #inherent, #default, ) @@ -703,9 +698,6 @@ fn create_style_chain_access( /// Creates the element's `Pack` implementation. fn create_native_elem_impl(element: &Elem) -> TokenStream { - let eval = quote! { ::typst::eval }; - let model = quote! { ::typst::model }; - let Elem { name, ident, title, scope, keywords, docs, .. } = element; let vtable_func = create_vtable_func(element); @@ -716,9 +708,9 @@ fn create_native_elem_impl(element: &Elem) -> TokenStream { .map(create_param_info); let scope = if *scope { - quote! { <#ident as #eval::NativeScope>::scope() } + quote! { <#ident as #foundations::NativeScope>::scope() } } else { - quote! { #eval::Scope::new() } + quote! { #foundations::Scope::new() } }; // Fields that can be accessed using the `field` method. @@ -729,37 +721,39 @@ fn create_native_elem_impl(element: &Elem) -> TokenStream { if field.ghost { quote! { - <#elem as #model::ElementFields>::Fields::#name => None, + <#elem as #foundations::ElementFields>::Fields::#name => None, } } else if field.inherent() { quote! { - <#elem as #model::ElementFields>::Fields::#name => Some( - ::typst::eval::IntoValue::into_value(self.#field_ident.clone()) + <#elem as #foundations::ElementFields>::Fields::#name => Some( + #foundations::IntoValue::into_value(self.#field_ident.clone()) ), } } else { quote! { - <#elem as #model::ElementFields>::Fields::#name => { - self.#field_ident.clone().map(::typst::eval::IntoValue::into_value) + <#elem as #foundations::ElementFields>::Fields::#name => { + self.#field_ident.clone().map(#foundations::IntoValue::into_value) } } } }); // Fields that can be set using the `set_field` method. - let field_set_matches = element.visible_fields() - .filter(|field| field.settable() && !field.synthesized && !field.ghost).map(|field| { - let elem = &element.ident; - let name = &field.enum_ident; - let field_ident = &field.ident; + let field_set_matches = element + .visible_fields() + .filter(|field| field.settable() && !field.synthesized && !field.ghost) + .map(|field| { + let elem = &element.ident; + let name = &field.enum_ident; + let field_ident = &field.ident; - quote! { - <#elem as #model::ElementFields>::Fields::#name => { - self.#field_ident = Some(::typst::eval::FromValue::from_value(value)?); - return Ok(()); + quote! { + <#elem as #foundations::ElementFields>::Fields::#name => { + self.#field_ident = Some(#foundations::FromValue::from_value(value)?); + return Ok(()); + } } - } - }); + }); // Fields that are inherent. let field_inherent_matches = element @@ -771,8 +765,8 @@ fn create_native_elem_impl(element: &Elem) -> TokenStream { let field_ident = &field.ident; quote! { - <#elem as #model::ElementFields>::Fields::#name => { - self.#field_ident = ::typst::eval::FromValue::from_value(value)?; + <#elem as #foundations::ElementFields>::Fields::#name => { + self.#field_ident = #foundations::FromValue::from_value(value)?; return Ok(()); } } @@ -790,13 +784,13 @@ fn create_native_elem_impl(element: &Elem) -> TokenStream { // Internal fields create an error that they are unknown. let unknown_field = format!("unknown field `{field_name}` on `{name}`"); quote! { - <#elem as #model::ElementFields>::Fields::#ident => ::typst::diag::bail!(#unknown_field), + <#elem as #foundations::ElementFields>::Fields::#ident => ::typst::diag::bail!(#unknown_field), } } else { // Fields that cannot be set create an error that they are not settable. let not_settable = format!("cannot set `{field_name}` on `{name}`"); quote! { - <#elem as #model::ElementFields>::Fields::#ident => ::typst::diag::bail!(#not_settable), + <#elem as #foundations::ElementFields>::Fields::#ident => ::typst::diag::bail!(#not_settable), } } }); @@ -824,15 +818,15 @@ fn create_native_elem_impl(element: &Elem) -> TokenStream { let field_ident = &field.ident; let field_call = if name.len() > 15 { - quote! { EcoString::from(#name).into() } + quote! { ::ecow::EcoString::from(#name).into() } } else { - quote! { EcoString::inline(#name).into() } + quote! { ::ecow::EcoString::inline(#name).into() } }; quote! { fields.insert( #field_call, - ::typst::eval::IntoValue::into_value(self.#field_ident.clone()) + #foundations::IntoValue::into_value(self.#field_ident.clone()) ); } }); @@ -847,16 +841,16 @@ fn create_native_elem_impl(element: &Elem) -> TokenStream { let field_ident = &field.ident; let field_call = if name.len() > 15 { - quote! { EcoString::from(#name).into() } + quote! { ::ecow::EcoString::from(#name).into() } } else { - quote! { EcoString::inline(#name).into() } + quote! { ::ecow::EcoString::inline(#name).into() } }; quote! { if let Some(value) = &self.#field_ident { fields.insert( #field_call, - ::typst::eval::IntoValue::into_value(value.clone()) + #foundations::IntoValue::into_value(value.clone()) ); } } @@ -889,7 +883,7 @@ fn create_native_elem_impl(element: &Elem) -> TokenStream { let label_field = element .unless_capability("Unlabellable", || { quote! { - self.label().map(::typst::eval::Value::Label) + self.label().map(#foundations::Value::Label) } }) .unwrap_or_else(|| quote! { None }); @@ -905,51 +899,51 @@ fn create_native_elem_impl(element: &Elem) -> TokenStream { let local_name = element .if_capability( "LocalName", - || quote! { Some(<#ident as ::typst::model::LocalName>::local_name) }, + || quote! { Some(<#ident as ::typst::text::LocalName>::local_name) }, ) .unwrap_or_else(|| quote! { None }); let unknown_field = format!("unknown field {{}} on {}", name); let label_error = format!("cannot set label on {}", name); let data = quote! { - #model::NativeElementData { + #foundations::NativeElementData { name: #name, title: #title, docs: #docs, keywords: &[#(#keywords),*], - construct: <#ident as #model::Construct>::construct, - set: <#ident as #model::Set>::set, + construct: <#ident as #foundations::Construct>::construct, + set: <#ident as #foundations::Set>::set, vtable: #vtable_func, field_id: |name| < - <#ident as #model::ElementFields>::Fields as ::std::str::FromStr + <#ident as #foundations::ElementFields>::Fields as ::std::str::FromStr >::from_str(name).ok().map(|id| id as u8), field_name: |id| < - <#ident as #model::ElementFields>::Fields as ::std::convert::TryFrom<u8> - >::try_from(id).ok().map(<#ident as #model::ElementFields>::Fields::to_str), + <#ident as #foundations::ElementFields>::Fields as ::std::convert::TryFrom<u8> + >::try_from(id).ok().map(<#ident as #foundations::ElementFields>::Fields::to_str), local_name: #local_name, - scope: #eval::Lazy::new(|| #scope), - params: #eval::Lazy::new(|| ::std::vec![#(#params),*]) + scope: #foundations::Lazy::new(|| #scope), + params: #foundations::Lazy::new(|| ::std::vec![#(#params),*]) } }; quote! { - impl #model::NativeElement for #ident { - fn data() -> &'static #model::NativeElementData { - static DATA: #model::NativeElementData = #data; + impl #foundations::NativeElement for #ident { + fn data() -> &'static #foundations::NativeElementData { + static DATA: #foundations::NativeElementData = #data; &DATA } - fn dyn_elem(&self) -> #model::Element { - #model::Element::of::<Self>() + fn dyn_elem(&self) -> #foundations::Element { + #foundations::Element::of::<Self>() } fn dyn_hash(&self, mut hasher: &mut dyn ::std::hash::Hasher) { <Self as ::std::hash::Hash>::hash(self, &mut hasher); } - fn dyn_eq(&self, other: &#model::Content) -> bool { + fn dyn_eq(&self, other: &#foundations::Content) -> bool { if let Some(other) = other.to::<Self>() { <Self as ::std::cmp::PartialEq>::eq(self, other) } else { @@ -957,7 +951,7 @@ fn create_native_elem_impl(element: &Elem) -> TokenStream { } } - fn dyn_clone(&self) -> ::std::sync::Arc<dyn #model::NativeElement> { + fn dyn_clone(&self) -> ::std::sync::Arc<dyn #foundations::NativeElement> { ::std::sync::Arc::new(Clone::clone(self)) } @@ -983,27 +977,27 @@ fn create_native_elem_impl(element: &Elem) -> TokenStream { } } - fn label(&self) -> Option<#model::Label> { + fn label(&self) -> Option<#foundations::Label> { #label } - fn set_label(&mut self, label: #model::Label) { + fn set_label(&mut self, label: #foundations::Label) { #set_label } - fn location(&self) -> Option<#model::Location> { + fn location(&self) -> Option<::typst::introspection::Location> { #location } - fn set_location(&mut self, location: #model::Location) { + fn set_location(&mut self, location: ::typst::introspection::Location) { #set_location } - fn push_guard(&mut self, guard: #model::Guard) { + fn push_guard(&mut self, guard: #foundations::Guard) { self.guards.push(guard); } - fn is_guarded(&self, guard: #model::Guard) -> bool { + fn is_guarded(&self, guard: #foundations::Guard) -> bool { self.guards.contains(&guard) } @@ -1023,30 +1017,30 @@ fn create_native_elem_impl(element: &Elem) -> TokenStream { #prepared } - fn field(&self, id: u8) -> Option<::typst::eval::Value> { - let id = <#ident as #model::ElementFields>::Fields::try_from(id).ok()?; + fn field(&self, id: u8) -> Option<#foundations::Value> { + let id = <#ident as #foundations::ElementFields>::Fields::try_from(id).ok()?; match id { - <#ident as #model::ElementFields>::Fields::Label => #label_field, + <#ident as #foundations::ElementFields>::Fields::Label => #label_field, #(#field_matches)* _ => None, } } - fn fields(&self) -> Dict { - let mut fields = Dict::new(); + fn fields(&self) -> #foundations::Dict { + let mut fields = #foundations::Dict::new(); #(#field_dict)* #(#field_opt_dict)* fields } - fn set_field(&mut self, id: u8, value: Value) -> ::typst::diag::StrResult<()> { - let id = <#ident as #model::ElementFields>::Fields::try_from(id) + fn set_field(&mut self, id: u8, value: #foundations::Value) -> ::typst::diag::StrResult<()> { + let id = <#ident as #foundations::ElementFields>::Fields::try_from(id) .map_err(|_| ::ecow::eco_format!(#unknown_field, id))?; match id { #(#field_set_matches)* #(#field_inherent_matches)* #(#field_not_set_matches)* - <#ident as #model::ElementFields>::Fields::Label => { + <#ident as #foundations::ElementFields>::Fields::Label => { ::typst::diag::bail!(#label_error); } } @@ -1087,18 +1081,18 @@ fn create_construct_impl(element: &Elem) -> TokenStream { .map(|field| &field.ident); quote! { - impl ::typst::model::Construct for #ident { + impl #foundations::Construct for #ident { fn construct( vm: &mut ::typst::eval::Vm, - args: &mut ::typst::eval::Args, - ) -> ::typst::diag::SourceResult<::typst::model::Content> { + args: &mut #foundations::Args, + ) -> ::typst::diag::SourceResult<#foundations::Content> { #(#pre)* let mut element = Self::new(#(#defaults),*); #(#handlers)* - Ok(::typst::model::Content::new(element)) + Ok(#foundations::Content::new(element)) } } } @@ -1119,12 +1113,12 @@ fn create_set_impl(element: &Elem) -> TokenStream { }); quote! { - impl ::typst::model::Set for #ident { + impl #foundations::Set for #ident { fn set( - vm: &mut Vm, - args: &mut ::typst::eval::Args, - ) -> ::typst::diag::SourceResult<::typst::model::Styles> { - let mut styles = ::typst::model::Styles::new(); + vm: &mut ::typst::eval::Vm, + args: &mut #foundations::Args, + ) -> ::typst::diag::SourceResult<#foundations::Styles> { + let mut styles = #foundations::Styles::new(); #(#handlers)* Ok(styles) } @@ -1135,7 +1129,7 @@ fn create_set_impl(element: &Elem) -> TokenStream { /// Creates the element's `Locatable` implementation. fn create_locatable_impl(element: &Elem) -> TokenStream { let ident = &element.ident; - quote! { impl ::typst::model::Locatable for #ident {} } + quote! { impl ::typst::introspection::Locatable for #ident {} } } /// Creates the element's `PartialEq` implementation. @@ -1159,12 +1153,12 @@ fn create_repr_impl(element: &Elem) -> TokenStream { let ident = &element.ident; let repr_format = format!("{}{{}}", element.name); quote! { - impl ::typst::eval::Repr for #ident { + impl #foundations::Repr for #ident { fn repr(&self) -> ::ecow::EcoString { - let fields = self.fields().into_iter() - .map(|(name, value)| eco_format!("{}: {}", name, value.repr())) + let fields = #foundations::NativeElement::fields(self).into_iter() + .map(|(name, value)| ::ecow::eco_format!("{}: {}", name, value.repr())) .collect::<Vec<_>>(); - ::ecow::eco_format!(#repr_format, ::typst::eval::repr::pretty_array_like(&fields, false)) + ::ecow::eco_format!(#repr_format, #foundations::repr::pretty_array_like(&fields, false)) } } } @@ -1185,7 +1179,7 @@ fn create_vtable_func(element: &Elem) -> TokenStream { if id == ::std::any::TypeId::of::<dyn #capability>() { let vtable = unsafe { let dangling = ::std::ptr::NonNull::<#ident>::dangling().as_ptr() as *const dyn #capability; - ::typst::model::fat::vtable(dangling) + ::typst::util::fat::vtable(dangling) }; return Some(vtable); } @@ -1224,20 +1218,20 @@ fn create_param_info(field: &Field) -> TokenStream { quote! { || { let typed: #default_ty = #default; - ::typst::eval::IntoValue::into_value(typed) + #foundations::IntoValue::into_value(typed) } } })); let ty = if *variadic { - quote! { <#ty as ::typst::eval::Container>::Inner } + quote! { <#ty as #foundations::Container>::Inner } } else { quote! { #ty } }; quote! { - ::typst::eval::ParamInfo { + #foundations::ParamInfo { name: #name, docs: #docs, - input: <#ty as ::typst::eval::Reflect>::input(), + input: <#ty as #foundations::Reflect>::input(), default: #default, positional: #positional, named: #named, diff --git a/crates/typst-macros/src/func.rs b/crates/typst-macros/src/func.rs index 9040abf9..8537ac4f 100644 --- a/crates/typst-macros/src/func.rs +++ b/crates/typst-macros/src/func.rs @@ -1,4 +1,14 @@ -use super::*; +use heck::ToKebabCase; +use proc_macro2::TokenStream; +use quote::quote; +use syn::parse::{Parse, ParseStream}; +use syn::{parse_quote, Ident, Result}; + +use crate::util::{ + determine_name_and_title, documentation, foundations, has_attr, kw, parse_attr, + parse_flag, parse_key_value, parse_string, parse_string_array, quote_option, + validate_attrs, +}; /// Expand the `#[func]` macro. pub fn func(stream: TokenStream, item: &syn::ItemFn) -> Result<TokenStream> { @@ -191,8 +201,6 @@ fn parse_param( /// Produce the function's definition. fn create(func: &Func, item: &syn::ItemFn) -> TokenStream { - let eval = quote! { ::typst::eval }; - let Func { docs, vis, ident, .. } = func; let item = rewrite_fn_item(item); let ty = create_func_ty(func); @@ -200,9 +208,9 @@ fn create(func: &Func, item: &syn::ItemFn) -> TokenStream { let creator = if ty.is_some() { quote! { - impl #eval::NativeFunc for #ident { - fn data() -> &'static #eval::NativeFuncData { - static DATA: #eval::NativeFuncData = #data; + impl #foundations::NativeFunc for #ident { + fn data() -> &'static #foundations::NativeFuncData { + static DATA: #foundations::NativeFuncData = #data; &DATA } } @@ -211,8 +219,8 @@ fn create(func: &Func, item: &syn::ItemFn) -> TokenStream { let ident_data = quote::format_ident!("{ident}_data"); quote! { #[doc(hidden)] - #vis fn #ident_data() -> &'static #eval::NativeFuncData { - static DATA: #eval::NativeFuncData = #data; + #vis fn #ident_data() -> &'static #foundations::NativeFuncData { + static DATA: #foundations::NativeFuncData = #data; &DATA } } @@ -231,8 +239,6 @@ fn create(func: &Func, item: &syn::ItemFn) -> TokenStream { /// Create native function data for the function. fn create_func_data(func: &Func) -> TokenStream { - let eval = quote! { ::typst::eval }; - let Func { ident, name, @@ -247,30 +253,30 @@ fn create_func_data(func: &Func) -> TokenStream { } = func; let scope = if *scope { - quote! { <#ident as #eval::NativeScope>::scope() } + quote! { <#ident as #foundations::NativeScope>::scope() } } else { - quote! { #eval::Scope::new() } + quote! { #foundations::Scope::new() } }; let closure = create_wrapper_closure(func); let params = func.special.self_.iter().chain(&func.params).map(create_param_info); let name = if *constructor { - quote! { <#parent as #eval::NativeType>::NAME } + quote! { <#parent as #foundations::NativeType>::NAME } } else { quote! { #name } }; quote! { - #eval::NativeFuncData { + #foundations::NativeFuncData { function: #closure, name: #name, title: #title, docs: #docs, keywords: &[#(#keywords),*], - scope: #eval::Lazy::new(|| #scope), - params: #eval::Lazy::new(|| ::std::vec![#(#params),*]), - returns: #eval::Lazy::new(|| <#returns as #eval::Reflect>::output()), + scope: #foundations::Lazy::new(|| #scope), + params: #foundations::Lazy::new(|| ::std::vec![#(#params),*]), + returns: #foundations::Lazy::new(|| <#returns as #foundations::Reflect>::output()), } } } @@ -335,7 +341,7 @@ fn create_wrapper_closure(func: &Func) -> TokenStream { #handlers #finish let output = #call; - ::typst::eval::IntoResult::into_result(output, args.span) + #foundations::IntoResult::into_result(output, args.span) } } } @@ -346,7 +352,7 @@ fn create_param_info(param: &Param) -> TokenStream { let positional = !named; let required = !named && default.is_none(); let ty = if *variadic || (*named && default.is_none()) { - quote! { <#ty as ::typst::eval::Container>::Inner } + quote! { <#ty as #foundations::Container>::Inner } } else { quote! { #ty } }; @@ -354,15 +360,15 @@ fn create_param_info(param: &Param) -> TokenStream { quote! { || { let typed: #ty = #default; - ::typst::eval::IntoValue::into_value(typed) + #foundations::IntoValue::into_value(typed) } } })); quote! { - ::typst::eval::ParamInfo { + #foundations::ParamInfo { name: #name, docs: #docs, - input: <#ty as ::typst::eval::Reflect>::input(), + input: <#ty as #foundations::Reflect>::input(), default: #default, positional: #positional, named: #named, diff --git a/crates/typst-macros/src/lib.rs b/crates/typst-macros/src/lib.rs index 87048ee5..28d02a6e 100644 --- a/crates/typst-macros/src/lib.rs +++ b/crates/typst-macros/src/lib.rs @@ -5,22 +5,15 @@ extern crate proc_macro; #[macro_use] mod util; mod cast; +mod category; mod elem; mod func; mod scope; mod symbols; mod ty; -use heck::*; use proc_macro::TokenStream as BoundaryStream; -use proc_macro2::TokenStream; -use quote::quote; -use syn::ext::IdentExt; -use syn::parse::{Parse, ParseStream, Parser}; -use syn::punctuated::Punctuated; -use syn::{parse_quote, DeriveInput, Ident, Result, Token}; - -use self::util::*; +use syn::DeriveInput; /// Makes a native Rust function usable as a Typst function. /// @@ -190,9 +183,6 @@ pub fn ty(stream: BoundaryStream, item: BoundaryStream) -> BoundaryStream { /// - `#[synthesized]`: The field cannot be specified in a constructor or set /// rule. Instead, it is added to an element before its show rule runs /// through the `Synthesize` trait. -/// - `#[variant]`: Allows setting the ID of a field's variant. This is used -/// for fields that are accessed in `typst` and not `typst-library`. It gives -/// the field a stable ID that can be used to access it. /// - `#[ghost]`: Allows creating fields that are only present in the style chain, /// this means that they *cannot* be accessed by the user, they cannot be set /// on an individual instantiated element, and must be set via the style chain. @@ -256,6 +246,15 @@ pub fn scope(stream: BoundaryStream, item: BoundaryStream) -> BoundaryStream { .into() } +/// Defines a category of definitions. +#[proc_macro_attribute] +pub fn category(stream: BoundaryStream, item: BoundaryStream) -> BoundaryStream { + let item = syn::parse_macro_input!(item as syn::Item); + category::category(stream.into(), item) + .unwrap_or_else(|err| err.to_compile_error()) + .into() +} + /// Implements `Reflect`, `FromValue`, and `IntoValue` for a type. /// /// - `Reflect` makes Typst's runtime aware of the type's characteristics. diff --git a/crates/typst-macros/src/scope.rs b/crates/typst-macros/src/scope.rs index 4aa17c6c..07a0efe0 100644 --- a/crates/typst-macros/src/scope.rs +++ b/crates/typst-macros/src/scope.rs @@ -1,6 +1,9 @@ use heck::ToKebabCase; +use proc_macro2::TokenStream; +use quote::quote; +use syn::{parse_quote, Result}; -use super::*; +use crate::util::{foundations, BareType}; /// Expand the `#[scope]` macro. pub fn scope(_: TokenStream, item: syn::Item) -> Result<TokenStream> { @@ -8,7 +11,6 @@ pub fn scope(_: TokenStream, item: syn::Item) -> Result<TokenStream> { bail!(item, "expected module or impl item"); }; - let eval = quote! { ::typst::eval }; let self_ty = &item.self_ty; let mut definitions = vec![]; @@ -43,13 +45,13 @@ pub fn scope(_: TokenStream, item: syn::Item) -> Result<TokenStream> { Ok(quote! { #base - impl #eval::NativeScope for #self_ty { - fn constructor() -> ::std::option::Option<&'static #eval::NativeFuncData> { + impl #foundations::NativeScope for #self_ty { + fn constructor() -> ::std::option::Option<&'static #foundations::NativeFuncData> { #constructor } - fn scope() -> #eval::Scope { - let mut scope = #eval::Scope::deduplicating(); + fn scope() -> #foundations::Scope { + let mut scope = #foundations::Scope::deduplicating(); #(#definitions;)* scope } @@ -92,7 +94,7 @@ fn handle_fn(self_ty: &syn::Type, item: &mut syn::ImplItemFn) -> Result<FnKind> } syn::Meta::List(list) => { let tokens = &list.tokens; - let meta: super::func::Meta = syn::parse2(tokens.clone())?; + let meta: crate::func::Meta = syn::parse2(tokens.clone())?; list.tokens = quote! { #tokens, parent = #self_ty }; if meta.constructor { return Ok(FnKind::Constructor(quote! { Some(#self_ty::#ident_data()) })); @@ -135,7 +137,7 @@ fn rewrite_primitive_base(item: &syn::ItemImpl, ident: &syn::Ident) -> TokenStre let ident_data = quote::format_ident!("{}_data", sig.ident); sigs.push(quote! { #sig; }); sigs.push(quote! { - fn #ident_data() -> &'static ::typst::eval::NativeFuncData; + fn #ident_data() -> &'static #foundations::NativeFuncData; }); } diff --git a/crates/typst-macros/src/symbols.rs b/crates/typst-macros/src/symbols.rs index 8ab47f08..2ddb922f 100644 --- a/crates/typst-macros/src/symbols.rs +++ b/crates/typst-macros/src/symbols.rs @@ -1,4 +1,9 @@ -use super::*; +use proc_macro2::TokenStream; +use quote::quote; +use syn::ext::IdentExt; +use syn::parse::{Parse, ParseStream, Parser}; +use syn::punctuated::Punctuated; +use syn::{Ident, Result, Token}; /// Expand the `symbols!` macro. pub fn symbols(stream: TokenStream) -> Result<TokenStream> { @@ -7,7 +12,7 @@ pub fn symbols(stream: TokenStream) -> Result<TokenStream> { let pairs = list.iter().map(|symbol| { let name = symbol.name.to_string(); let kind = match &symbol.kind { - Kind::Single(c) => quote! { typst::eval::Symbol::single(#c), }, + Kind::Single(c) => quote! { ::typst::symbols::Symbol::single(#c), }, Kind::Multiple(variants) => { let variants = variants.iter().map(|variant| { let name = &variant.name; @@ -15,7 +20,7 @@ pub fn symbols(stream: TokenStream) -> Result<TokenStream> { quote! { (#name, #c) } }); quote! { - typst::eval::Symbol::list(&[#(#variants),*]) + ::typst::symbols::Symbol::list(&[#(#variants),*]) } } }; diff --git a/crates/typst-macros/src/ty.rs b/crates/typst-macros/src/ty.rs index df60e7bb..23f818bd 100644 --- a/crates/typst-macros/src/ty.rs +++ b/crates/typst-macros/src/ty.rs @@ -1,6 +1,12 @@ -use syn::Attribute; +use proc_macro2::TokenStream; +use quote::quote; +use syn::parse::{Parse, ParseStream}; +use syn::{Attribute, Ident, Result}; -use super::*; +use crate::util::{ + determine_name_and_title, documentation, foundations, kw, parse_flag, parse_string, + parse_string_array, BareType, +}; /// Expand the `#[ty]` macro. pub fn ty(stream: TokenStream, item: syn::Item) -> Result<TokenStream> { @@ -68,44 +74,42 @@ fn parse(meta: Meta, ident: Ident, attrs: &[Attribute]) -> Result<Type> { /// Produce the output of the macro. fn create(ty: &Type, item: Option<&syn::Item>) -> TokenStream { - let eval = quote! { ::typst::eval }; - let Type { ident, name, long, title, docs, keywords, scope, .. } = ty; let constructor = if *scope { - quote! { <#ident as #eval::NativeScope>::constructor() } + quote! { <#ident as #foundations::NativeScope>::constructor() } } else { quote! { None } }; let scope = if *scope { - quote! { <#ident as #eval::NativeScope>::scope() } + quote! { <#ident as #foundations::NativeScope>::scope() } } else { - quote! { #eval::Scope::new() } + quote! { #foundations::Scope::new() } }; let data = quote! { - #eval::NativeTypeData { + #foundations::NativeTypeData { name: #name, long_name: #long, title: #title, docs: #docs, keywords: &[#(#keywords),*], - constructor: #eval::Lazy::new(|| #constructor), - scope: #eval::Lazy::new(|| #scope), + constructor: #foundations::Lazy::new(|| #constructor), + scope: #foundations::Lazy::new(|| #scope), } }; quote! { #item - impl #eval::NativeType for #ident { + impl #foundations::NativeType for #ident { const NAME: &'static str = #name; - fn data() -> &'static #eval::NativeTypeData { - static DATA: #eval::NativeTypeData = #data; + fn data() -> &'static #foundations::NativeTypeData { + static DATA: #foundations::NativeTypeData = #data; &DATA } } diff --git a/crates/typst-macros/src/util.rs b/crates/typst-macros/src/util.rs index 790db3e1..32c0aa4e 100644 --- a/crates/typst-macros/src/util.rs +++ b/crates/typst-macros/src/util.rs @@ -1,8 +1,9 @@ -use quote::ToTokens; +use heck::{ToKebabCase, ToTitleCase}; +use proc_macro2::TokenStream; +use quote::{quote, ToTokens}; +use syn::parse::{Parse, ParseStream}; use syn::token::Token; -use syn::Attribute; - -use super::*; +use syn::{Attribute, Ident, Result, Token}; /// Return an error at the given item. macro_rules! bail { @@ -199,6 +200,16 @@ impl<T: Parse> Parse for Array<T> { } } +/// Shorthand for `::typst::foundations`. +#[allow(non_camel_case_types)] +pub struct foundations; + +impl quote::ToTokens for foundations { + fn to_tokens(&self, tokens: &mut TokenStream) { + quote! { ::typst::foundations }.to_tokens(tokens); + } +} + /// For parsing attributes of the form: /// #[attr( /// statement; @@ -220,15 +231,6 @@ impl Parse for BlockWithReturn { } } -pub mod kw { - syn::custom_keyword!(name); - syn::custom_keyword!(title); - syn::custom_keyword!(scope); - syn::custom_keyword!(constructor); - syn::custom_keyword!(keywords); - syn::custom_keyword!(parent); -} - /// Parse a bare `type Name;` item. pub struct BareType { pub attrs: Vec<Attribute>, @@ -239,7 +241,7 @@ pub struct BareType { impl Parse for BareType { fn parse(input: ParseStream) -> Result<Self> { - Ok(BareType { + Ok(Self { attrs: input.call(Attribute::parse_outer)?, type_token: input.parse()?, ident: input.parse()?, @@ -247,3 +249,12 @@ impl Parse for BareType { }) } } + +pub mod kw { + syn::custom_keyword!(name); + syn::custom_keyword!(title); + syn::custom_keyword!(scope); + syn::custom_keyword!(constructor); + syn::custom_keyword!(keywords); + syn::custom_keyword!(parent); +} |
