summaryrefslogtreecommitdiff
path: root/library/src/compute/foundations.rs
blob: bad9f8ab1dad6800b185035cce7a88b961353cb3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use crate::prelude::*;

/// Determine a value's type.
///
/// Returns the name of the value's type.
///
/// ## Example
/// ```example
/// #type(12) \
/// #type(14.7) \
/// #type("hello") \
/// #type(none) \
/// #type([Hi]) \
/// #type(x => x + 1)
/// ```
///
/// Display: Type
/// Category: foundations
/// Returns: string
#[func]
pub fn type_(
    /// The value whose type's to determine.
    value: Value,
) -> Value {
    value.type_name().into()
}

/// The string representation of a value.
///
/// When inserted into content, most values are displayed as this representation
/// in monospace with syntax-highlighting. The exceptions are `{none}`,
/// integers, floats, strings, content, and functions.
///
/// **Note:** This function is for debugging purposes. Its output should not be
/// considered stable and may change at any time!
///
/// ## Example
/// ```example
/// #none vs #repr(none) \
/// #"hello" vs #repr("hello") \
/// #(1, 2) vs #repr((1, 2)) \
/// #[*Hi*] vs #repr([*Hi*])
/// ```
///
/// Display: Representation
/// Category: foundations
/// Returns: string
#[func]
pub fn repr(
    /// The value whose string representation to produce.
    value: Value,
) -> Value {
    value.repr().into()
}

/// Fail with an error.
///
/// ## Example
/// The code below produces the error `panicked with: "this is wrong"`.
/// ```typ
/// #panic("this is wrong")
/// ```
///
/// Display: Panic
/// Category: foundations
/// Returns:
#[func]
pub fn panic(
    /// The values to panic with.
    #[variadic]
    values: Vec<Value>,
) -> Value {
    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());
        }
    }
    bail!(args.span, msg);
}

/// Ensure that a condition is fulfilled.
///
/// Fails with an error if the condition is not fulfilled. Does not
/// produce any output in the document.
///
/// ## Example
/// ```typ
/// #assert(1 < 2, message: "math broke")
/// ```
///
/// Display: Assert
/// Category: foundations
/// Returns:
#[func]
pub fn assert(
    /// The condition that must be true for the assertion to pass.
    condition: bool,
    /// The error message when the assertion fails.
    #[named]
    #[default]
    message: Option<EcoString>,
) -> Value {
    if !condition {
        if let Some(message) = message {
            bail!(args.span, "assertion failed: {}", message);
        } else {
            bail!(args.span, "assertion failed");
        }
    }
    Value::None
}

/// Evaluate 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("[*Strong text*]")
/// ```
///
/// Display: Evaluate
/// Category: foundations
/// Returns: any
#[func]
pub fn eval(
    /// A string of Typst code to evaluate.
    ///
    /// The code in the string cannot interact with the file system.
    source: Spanned<String>,
) -> Value {
    let Spanned { v: text, span } = source;
    typst::eval::eval_string(vm.world(), &text, span)?
}