diff options
| author | Laurenz <laurmaedje@gmail.com> | 2024-10-27 19:04:55 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-27 18:04:55 +0000 |
| commit | be7cfc85d08c545abfac08098b7b33b4bd71f37e (patch) | |
| tree | f4137fa2aaa57babae1f7603a9b2ed7e688f43d8 /crates/typst-library/src/foundations/mod.rs | |
| parent | b8034a343831e8609aec2ec81eb7eeda57aa5d81 (diff) | |
Split out four new crates (#5302)
Diffstat (limited to 'crates/typst-library/src/foundations/mod.rs')
| -rw-r--r-- | crates/typst-library/src/foundations/mod.rs | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/crates/typst-library/src/foundations/mod.rs b/crates/typst-library/src/foundations/mod.rs new file mode 100644 index 00000000..a6d6c253 --- /dev/null +++ b/crates/typst-library/src/foundations/mod.rs @@ -0,0 +1,302 @@ +//! Foundational types and functions. + +pub mod calc; +pub mod ops; +pub mod repr; +pub mod sys; + +mod args; +mod array; +mod auto; +mod bool; +mod bytes; +mod cast; +mod content; +mod context; +mod datetime; +mod decimal; +mod dict; +mod duration; +mod element; +mod fields; +mod float; +mod func; +mod int; +mod label; +mod module; +mod none; +mod plugin; +mod scope; +mod selector; +mod str; +mod styles; +mod symbol; +mod ty; +mod value; +mod version; + +pub use self::args::*; +pub use self::array::*; +pub use self::auto::*; +pub use self::bytes::*; +pub use self::cast::*; +pub use self::content::*; +pub use self::context::*; +pub use self::datetime::*; +pub use self::decimal::*; +pub use self::dict::*; +pub use self::duration::*; +pub use self::element::*; +pub use self::fields::*; +pub use self::float::*; +pub use self::func::*; +pub use self::int::*; +pub use self::label::*; +pub use self::module::*; +pub use self::none::*; +pub use self::plugin::*; +pub use self::repr::Repr; +pub use self::scope::*; +pub use self::selector::*; +pub use self::str::*; +pub use self::styles::*; +pub use self::symbol::*; +pub use self::ty::*; +pub use self::value::*; +pub use self::version::*; +pub use typst_macros::{scope, ty}; + +#[rustfmt::skip] +#[doc(hidden)] +pub use { + ecow::{eco_format, eco_vec}, + indexmap::IndexMap, + once_cell::sync::Lazy, +}; + +use ecow::EcoString; +use typst_syntax::Spanned; + +use crate::diag::{bail, SourceResult, StrResult}; +use crate::engine::Engine; +use crate::routines::EvalMode; + +/// Foundational types and functions. +/// +/// Here, you'll find documentation for basic data types like [integers]($int) +/// and [strings]($str) as well as details about core computational functions. +#[category] +pub static FOUNDATIONS: Category; + +/// Hook up all `foundations` definitions. +pub(super) fn define(global: &mut Scope, inputs: Dict) { + global.category(FOUNDATIONS); + global.define_type::<bool>(); + global.define_type::<i64>(); + global.define_type::<f64>(); + global.define_type::<Str>(); + global.define_type::<Label>(); + global.define_type::<Bytes>(); + global.define_type::<Content>(); + global.define_type::<Array>(); + global.define_type::<Dict>(); + global.define_type::<Func>(); + global.define_type::<Args>(); + global.define_type::<Type>(); + global.define_type::<Module>(); + global.define_type::<Regex>(); + global.define_type::<Selector>(); + global.define_type::<Datetime>(); + global.define_type::<Decimal>(); + global.define_type::<Symbol>(); + global.define_type::<Duration>(); + global.define_type::<Version>(); + global.define_type::<Plugin>(); + global.define_func::<repr::repr>(); + global.define_func::<panic>(); + global.define_func::<assert>(); + global.define_func::<eval>(); + global.define_func::<style>(); + global.define_module(calc::module()); + global.define_module(sys::module(inputs)); +} + +/// Fails with an error. +/// +/// Arguments are displayed to the user (not rendered in the document) as +/// strings, converting with `repr` if necessary. +/// +/// # Example +/// The code below produces the error `panicked with: "this is wrong"`. +/// ```typ +/// #panic("this is wrong") +/// ``` +#[func(keywords = ["error"])] +pub fn panic( + /// The values to panic with and display to the user. + #[variadic] + values: Vec<Value>, +) -> StrResult<Never> { + let mut msg = EcoString::from("panicked"); + if !values.is_empty() { + msg.push_str(" with: "); + for (i, value) in values.iter().enumerate() { + if i > 0 { + msg.push_str(", "); + } + msg.push_str(&value.repr()); + } + } + Err(msg) +} + +/// Ensures that a condition is fulfilled. +/// +/// Fails with an error if the condition is not fulfilled. Does not +/// produce any output in the document. +/// +/// If you wish to test equality between two values, see +/// [`assert.eq`]($assert.eq) and [`assert.ne`]($assert.ne). +/// +/// # Example +/// ```typ +/// #assert(1 < 2, message: "math broke") +/// ``` +#[func(scope)] +pub fn assert( + /// The condition that must be true for the assertion to pass. + condition: bool, + /// The error message when the assertion fails. + #[named] + message: Option<EcoString>, +) -> StrResult<NoneValue> { + if !condition { + if let Some(message) = message { + bail!("assertion failed: {message}"); + } else { + bail!("assertion failed"); + } + } + Ok(NoneValue) +} + +#[scope] +impl assert { + /// Ensures that two values are equal. + /// + /// Fails with an error if the first value is not equal to the second. Does not + /// produce any output in the document. + /// + /// ```typ + /// #assert.eq(10, 10) + /// ``` + #[func(title = "Assert Equal")] + pub fn eq( + /// The first value to compare. + left: Value, + /// The second value to compare. + right: Value, + /// An optional message to display on error instead of the representations + /// of the compared values. + #[named] + message: Option<EcoString>, + ) -> StrResult<NoneValue> { + if left != right { + if let Some(message) = message { + bail!("equality assertion failed: {message}"); + } else { + bail!( + "equality assertion failed: value {} was not equal to {}", + left.repr(), + right.repr() + ); + } + } + Ok(NoneValue) + } + + /// Ensures that two values are not equal. + /// + /// Fails with an error if the first value is equal to the second. Does not + /// produce any output in the document. + /// + /// ```typ + /// #assert.ne(3, 4) + /// ``` + #[func(title = "Assert Not Equal")] + pub fn ne( + /// The first value to compare. + left: Value, + /// The second value to compare. + right: Value, + /// An optional message to display on error instead of the representations + /// of the compared values. + #[named] + message: Option<EcoString>, + ) -> StrResult<NoneValue> { + if left == right { + if let Some(message) = message { + bail!("inequality assertion failed: {message}"); + } else { + bail!( + "inequality assertion failed: value {} was equal to {}", + left.repr(), + right.repr() + ); + } + } + Ok(NoneValue) + } +} + +/// Evaluates a string as Typst code. +/// +/// This function should only be used as a last resort. +/// +/// # Example +/// ```example +/// #eval("1 + 1") \ +/// #eval("(1, 2, 3, 4)").len() \ +/// #eval("*Markup!*", mode: "markup") \ +/// ``` +#[func(title = "Evaluate")] +pub fn eval( + /// The engine. + engine: &mut Engine, + /// A string of Typst code to evaluate. + source: Spanned<String>, + /// The [syntactical mode]($reference/syntax/#modes) in which the string is + /// parsed. + /// + /// ```example + /// #eval("= Heading", mode: "markup") + /// #eval("1_2^3", mode: "math") + /// ``` + #[named] + #[default(EvalMode::Code)] + mode: EvalMode, + /// A scope of definitions that are made available. + /// + /// ```example + /// #eval("x + 1", scope: (x: 2)) \ + /// #eval( + /// "abc/xyz", + /// mode: "math", + /// scope: ( + /// abc: $a + b + c$, + /// xyz: $x + y + z$, + /// ), + /// ) + /// ``` + #[named] + #[default] + scope: Dict, +) -> SourceResult<Value> { + let Spanned { v: text, span } = source; + let dict = scope; + let mut scope = Scope::new(); + for (key, value) in dict { + scope.define_spanned(key, value, span); + } + (engine.routines.eval_string)(engine.routines, engine.world, &text, span, mode, scope) +} |
