summaryrefslogtreecommitdiff
path: root/crates/typst-macros
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-11-23 16:25:49 +0100
committerLaurenz <laurmaedje@gmail.com>2023-11-24 12:30:02 +0100
commit7eebafa7837ec173a7b2064ae60fd45b5413d17c (patch)
treeb63b302b6d7747bcbb28571713745b9ca1aa83a4 /crates/typst-macros
parent76e173b78b511b506b928c27ac360f75fa455747 (diff)
Merge `typst` and `typst-library`
Diffstat (limited to 'crates/typst-macros')
-rw-r--r--crates/typst-macros/src/cast.rs59
-rw-r--r--crates/typst-macros/src/category.rs57
-rw-r--r--crates/typst-macros/src/elem.rs234
-rw-r--r--crates/typst-macros/src/func.rs50
-rw-r--r--crates/typst-macros/src/lib.rs23
-rw-r--r--crates/typst-macros/src/scope.rs18
-rw-r--r--crates/typst-macros/src/symbols.rs11
-rw-r--r--crates/typst-macros/src/ty.rs30
-rw-r--r--crates/typst-macros/src/util.rs39
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);
+}