summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/typst-macros/src/scope.rs77
-rw-r--r--crates/typst/src/foundations/calc.rs1
-rw-r--r--crates/typst/src/foundations/float.rs18
-rw-r--r--crates/typst/src/foundations/repr.rs6
-rw-r--r--tests/ref/float-repr.pngbin2443 -> 2497 bytes
-rw-r--r--tests/ref/grid-rowspan-split-15.pngbin2948 -> 3058 bytes
-rw-r--r--tests/ref/ops-multiply-inf-with-length.pngbin2414 -> 2479 bytes
-rw-r--r--tests/suite/foundations/float.typ18
-rw-r--r--tests/suite/scripting/ops.typ4
9 files changed, 76 insertions, 48 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 {
diff --git a/tests/ref/float-repr.png b/tests/ref/float-repr.png
index 7b49e9d1..e73ee328 100644
--- a/tests/ref/float-repr.png
+++ b/tests/ref/float-repr.png
Binary files differ
diff --git a/tests/ref/grid-rowspan-split-15.png b/tests/ref/grid-rowspan-split-15.png
index bbefe0da..bd435f3c 100644
--- a/tests/ref/grid-rowspan-split-15.png
+++ b/tests/ref/grid-rowspan-split-15.png
Binary files differ
diff --git a/tests/ref/ops-multiply-inf-with-length.png b/tests/ref/ops-multiply-inf-with-length.png
index 0662d568..b7c458a1 100644
--- a/tests/ref/ops-multiply-inf-with-length.png
+++ b/tests/ref/ops-multiply-inf-with-length.png
Binary files differ
diff --git a/tests/suite/foundations/float.typ b/tests/suite/foundations/float.typ
index 206013ac..01769260 100644
--- a/tests/suite/foundations/float.typ
+++ b/tests/suite/foundations/float.typ
@@ -18,7 +18,7 @@
--- float-is-nan ---
// Test float `is-nan()`.
-#test(float(calc.nan).is-nan(), true)
+#test(float(float.nan).is-nan(), true)
#test(float(10).is-nan(), false)
#test(float(calc.inf).is-nan(), false)
#test(float(-calc.inf).is-nan(), false)
@@ -29,7 +29,7 @@
#test(float(-calc.inf).is-infinite(), true)
#test(float(10).is-infinite(), false)
#test(float(-10).is-infinite(), false)
-#test(float(calc.nan).is-infinite(), false)
+#test(float(float.nan).is-infinite(), false)
--- float-signum ---
// Test float `signum()`
@@ -40,7 +40,7 @@
#test(float(-10.0).signum(), -1.0)
#test(float(calc.inf).signum(), 1.0)
#test(float(-calc.inf).signum(), -1.0)
-#test(float(calc.nan).signum().is-nan(), true)
+#test(float(float.nan).signum().is-nan(), true)
--- float-repr ---
// Test the `repr` function with floats.
@@ -55,9 +55,9 @@
#repr(-0987654321.0) \
#repr(-3.14) \
#repr(4.0 - 8.0) \
-#repr(calc.inf) \
-#repr(-calc.inf) \
-#repr(calc.nan)
+#repr(float.inf) \
+#repr(-float.inf) \
+#repr(float.nan)
--- float-display ---
// Test floats.
@@ -72,6 +72,6 @@
#(-0987654321.0) \
#(-3.14) \
#(4.0 - 8.0) \
-#calc.inf \
-#(-calc.inf) \
-#calc.nan
+#float.inf \
+#(-float.inf) \
+#float.nan
diff --git a/tests/suite/scripting/ops.typ b/tests/suite/scripting/ops.typ
index 0df4b82d..1c957217 100644
--- a/tests/suite/scripting/ops.typ
+++ b/tests/suite/scripting/ops.typ
@@ -335,7 +335,7 @@
#(1em <= 10pt)
--- ops-compare-normal-float-with-nan ---
-// Error: 3-22 cannot compare 2.2 with calc.nan
+// Error: 3-22 cannot compare 2.2 with float.nan
#(2.2 <= float("nan"))
--- ops-compare-int-and-str ---
@@ -343,7 +343,7 @@
#((0, 1, 3) > (0, 1, "a"))
--- ops-compare-array-nested-failure ---
-// Error: 3-42 cannot compare 3.5 with calc.nan
+// Error: 3-42 cannot compare 3.5 with float.nan
#((0, "a", 3.5) <= (0, "a", float("nan")))
--- ops-divide-by-zero-float ---