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
|
//! Handles special built-in methods on values.
use typst_library::diag::{At, SourceResult};
use typst_library::foundations::{Args, Str, Type, Value};
use typst_syntax::Span;
/// Whether a specific method is mutating.
pub(crate) fn is_mutating_method(method: &str) -> bool {
matches!(method, "push" | "pop" | "insert" | "remove")
}
/// Whether a specific method is an accessor.
pub(crate) fn is_accessor_method(method: &str) -> bool {
matches!(method, "first" | "last" | "at")
}
/// Call a mutating method on a value.
pub(crate) fn call_method_mut(
value: &mut Value,
method: &str,
mut args: Args,
span: Span,
) -> SourceResult<Value> {
let ty = value.ty();
let missing = || Err(missing_method(ty, method)).at(span);
let mut output = Value::None;
match value {
Value::Array(array) => match method {
"push" => array.push(args.expect("value")?),
"pop" => output = array.pop().at(span)?,
"insert" => {
array.insert(args.expect("index")?, args.expect("value")?).at(span)?
}
"remove" => {
output = array
.remove(args.expect("index")?, args.named("default")?)
.at(span)?
}
_ => return missing(),
},
Value::Dict(dict) => match method {
"insert" => dict.insert(args.expect::<Str>("key")?, args.expect("value")?),
"remove" => {
output =
dict.remove(args.expect("key")?, args.named("default")?).at(span)?
}
_ => return missing(),
},
_ => return missing(),
}
args.finish()?;
Ok(output)
}
/// Call an accessor method on a value.
pub(crate) fn call_method_access<'a>(
value: &'a mut Value,
method: &str,
mut args: Args,
span: Span,
) -> SourceResult<&'a mut Value> {
let ty = value.ty();
let missing = || Err(missing_method(ty, method)).at(span);
let slot = match value {
Value::Array(array) => match method {
"first" => array.first_mut().at(span)?,
"last" => array.last_mut().at(span)?,
"at" => array.at_mut(args.expect("index")?).at(span)?,
_ => return missing(),
},
Value::Dict(dict) => match method {
"at" => dict.at_mut(&args.expect::<Str>("key")?).at(span)?,
_ => return missing(),
},
_ => return missing(),
};
args.finish()?;
Ok(slot)
}
/// The missing method error message.
#[cold]
fn missing_method(ty: Type, method: &str) -> String {
format!("type {ty} has no method `{method}`")
}
|