mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
92 lines
2.6 KiB
Rust
92 lines
2.6 KiB
Rust
//! 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}`")
|
|
}
|