diff options
| author | Malo <57839069+MDLC01@users.noreply.github.com> | 2024-08-15 22:04:50 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-08-15 20:04:50 +0000 |
| commit | c43997de0a4fa958bc6bdfd5c29a47e1ba14800d (patch) | |
| tree | 7798325886b6a03b79be85f29ee8339a9b4dea93 /crates | |
| parent | 0edd8ec93d16a397e58cebaa215b6c14cd24de8f (diff) | |
Move `calc.nan` to `float.nan` and add `float.inf` (#4733)
Diffstat (limited to 'crates')
| -rw-r--r-- | crates/typst-macros/src/scope.rs | 77 | ||||
| -rw-r--r-- | crates/typst/src/foundations/calc.rs | 1 | ||||
| -rw-r--r-- | crates/typst/src/foundations/float.rs | 18 | ||||
| -rw-r--r-- | crates/typst/src/foundations/repr.rs | 6 |
4 files changed, 65 insertions, 37 deletions
diff --git a/crates/typst-macros/src/scope.rs b/crates/typst-macros/src/scope.rs index 07a0efe0..d86c6aea 100644 --- a/crates/typst-macros/src/scope.rs +++ b/crates/typst-macros/src/scope.rs @@ -13,11 +13,26 @@ pub fn scope(_: TokenStream, item: syn::Item) -> Result<TokenStream> { let self_ty = &item.self_ty; + let mut primitive_ident_ext = None; + if let syn::Type::Path(syn::TypePath { path, .. }) = self_ty.as_ref() { + if let Some(ident) = path.get_ident() { + if is_primitive(ident) { + let ident_ext = quote::format_ident!("{ident}Ext"); + primitive_ident_ext = Some(ident_ext); + } + } + } + + let self_ty_expr = match &primitive_ident_ext { + None => quote! { #self_ty }, + Some(ident_ext) => quote! { <#self_ty as #ident_ext> }, + }; + let mut definitions = vec![]; let mut constructor = quote! { None }; for child in &mut item.items { let def = match child { - syn::ImplItem::Const(item) => handle_const(self_ty, item)?, + syn::ImplItem::Const(item) => handle_const(&self_ty_expr, item)?, syn::ImplItem::Fn(item) => match handle_fn(self_ty, item)? { FnKind::Member(tokens) => tokens, FnKind::Constructor(tokens) => { @@ -33,14 +48,10 @@ pub fn scope(_: TokenStream, item: syn::Item) -> Result<TokenStream> { item.items.retain(|item| !matches!(item, syn::ImplItem::Verbatim(_))); - let mut base = quote! { #item }; - if let syn::Type::Path(syn::TypePath { path, .. }) = self_ty.as_ref() { - if let Some(ident) = path.get_ident() { - if is_primitive(ident) { - base = rewrite_primitive_base(&item, ident); - } - } - } + let base = match &primitive_ident_ext { + None => quote! { #item }, + Some(ident_ext) => rewrite_primitive_base(&item, ident_ext), + }; Ok(quote! { #base @@ -60,7 +71,7 @@ pub fn scope(_: TokenStream, item: syn::Item) -> Result<TokenStream> { } /// Process a const item and returns its definition. -fn handle_const(self_ty: &syn::Type, item: &syn::ImplItemConst) -> Result<TokenStream> { +fn handle_const(self_ty: &TokenStream, item: &syn::ImplItemConst) -> Result<TokenStream> { let ident = &item.ident; let name = ident.to_string().to_kebab_case(); Ok(quote! { scope.define(#name, #self_ty::#ident) }) @@ -117,31 +128,39 @@ fn is_primitive(ident: &syn::Ident) -> bool { } /// Rewrite an impl block for a primitive into a trait + trait impl. -fn rewrite_primitive_base(item: &syn::ItemImpl, ident: &syn::Ident) -> TokenStream { +fn rewrite_primitive_base(item: &syn::ItemImpl, ident_ext: &syn::Ident) -> TokenStream { let mut sigs = vec![]; let mut items = vec![]; for sub in &item.items { - let syn::ImplItem::Fn(mut func) = sub.clone() else { continue }; - func.vis = syn::Visibility::Inherited; - items.push(func.clone()); - - let mut sig = func.sig; - let inputs = sig.inputs.iter().cloned().map(|mut input| { - if let syn::FnArg::Typed(typed) = &mut input { - typed.attrs.clear(); + match sub.clone() { + syn::ImplItem::Fn(mut func) => { + func.vis = syn::Visibility::Inherited; + items.push(func.clone()); + + let mut sig = func.sig; + let inputs = sig.inputs.iter().cloned().map(|mut input| { + if let syn::FnArg::Typed(typed) = &mut input { + typed.attrs.clear(); + } + input + }); + sig.inputs = parse_quote! { #(#inputs),* }; + + let ident_data = quote::format_ident!("{}_data", sig.ident); + sigs.push(quote! { #sig; }); + sigs.push(quote! { + fn #ident_data() -> &'static #foundations::NativeFuncData; + }); + } + + syn::ImplItem::Const(cons) => { + sigs.push(quote! { #cons }); } - input - }); - sig.inputs = parse_quote! { #(#inputs),* }; - - let ident_data = quote::format_ident!("{}_data", sig.ident); - sigs.push(quote! { #sig; }); - sigs.push(quote! { - fn #ident_data() -> &'static #foundations::NativeFuncData; - }); + + _ => {} + } } - let ident_ext = quote::format_ident!("{ident}Ext"); let self_ty = &item.self_ty; quote! { trait #ident_ext { diff --git a/crates/typst/src/foundations/calc.rs b/crates/typst/src/foundations/calc.rs index d07b23c5..287bc828 100644 --- a/crates/typst/src/foundations/calc.rs +++ b/crates/typst/src/foundations/calc.rs @@ -50,7 +50,6 @@ pub fn module() -> Module { scope.define_func::<rem_euclid>(); scope.define_func::<quo>(); scope.define("inf", f64::INFINITY); - scope.define("nan", f64::NAN); scope.define("pi", std::f64::consts::PI); scope.define("tau", std::f64::consts::TAU); scope.define("e", std::f64::consts::E); diff --git a/crates/typst/src/foundations/float.rs b/crates/typst/src/foundations/float.rs index d346c329..fd094950 100644 --- a/crates/typst/src/foundations/float.rs +++ b/crates/typst/src/foundations/float.rs @@ -13,6 +13,9 @@ use crate::layout::Ratio; /// /// You can convert a value to a float with this type's constructor. /// +/// NaN and positive infinity are available as `{float.nan}` and `{float.inf}` +/// respectively. +/// /// # Example /// ```example /// #3.14 \ @@ -24,6 +27,13 @@ type f64; #[scope] impl f64 { + /// Positive infinity. + const INF: f64 = f64::INFINITY; + + /// A NaN value, as defined by the + /// [IEEE 754 standard](https://en.wikipedia.org/wiki/IEEE_754). + const NAN: f64 = f64::NAN; + /// Converts a value to a float. /// /// - Booleans are converted to `0.0` or `1.0`. @@ -58,7 +68,7 @@ impl f64 { /// ```example /// #float.is-nan(0) \ /// #float.is-nan(1) \ - /// #float.is-nan(calc.nan) + /// #float.is-nan(float.nan) /// ``` #[func] pub fn is_nan(self) -> bool { @@ -73,7 +83,7 @@ impl f64 { /// ```example /// #float.is-infinite(0) \ /// #float.is-infinite(1) \ - /// #float.is-infinite(calc.inf) + /// #float.is-infinite(float.inf) /// ``` #[func] pub fn is_infinite(self) -> bool { @@ -84,13 +94,13 @@ impl f64 { /// /// - If the number is positive (including `{+0.0}`), returns `{1.0}`. /// - If the number is negative (including `{-0.0}`), returns `{-1.0}`. - /// - If the number is `{calc.nan}`, returns `{calc.nan}`. + /// - If the number is `{float.nan}`, returns `{float.nan}`. /// /// ```example /// #(5.0).signum() \ /// #(-5.0).signum() \ /// #(0.0).signum() \ - /// #calc.nan.signum() + /// #float.nan.signum() /// ``` #[func] pub fn signum(self) -> f64 { diff --git a/crates/typst/src/foundations/repr.rs b/crates/typst/src/foundations/repr.rs index 68c94c56..9c098bd1 100644 --- a/crates/typst/src/foundations/repr.rs +++ b/crates/typst/src/foundations/repr.rs @@ -76,7 +76,7 @@ pub fn format_int_with_base(mut n: i64, base: i64) -> EcoString { /// unit, all with a single allocation. /// /// The returned string is always valid Typst code. As such, it might not be a -/// float literal. For example, it may return `"calc.inf"`. +/// float literal. For example, it may return `"float.inf"`. pub fn format_float( mut value: f64, precision: Option<u8>, @@ -91,10 +91,10 @@ pub fn format_float( // when necessary. let unit_multiplication = if unit.is_empty() { "" } else { " * 1" }; if value.is_nan() { - eco_format!("calc.nan{unit_multiplication}{unit}") + eco_format!("float.nan{unit_multiplication}{unit}") } else if value.is_infinite() { let sign = if value < 0.0 { "-" } else { "" }; - eco_format!("{sign}calc.inf{unit_multiplication}{unit}") + eco_format!("{sign}float.inf{unit_multiplication}{unit}") } else if force_separator { eco_format!("{value:?}{unit}") } else { |
