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-eval/src/methods.rs | |
| parent | b8034a343831e8609aec2ec81eb7eeda57aa5d81 (diff) | |
Split out four new crates (#5302)
Diffstat (limited to 'crates/typst-eval/src/methods.rs')
| -rw-r--r-- | crates/typst-eval/src/methods.rs | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/crates/typst-eval/src/methods.rs b/crates/typst-eval/src/methods.rs new file mode 100644 index 00000000..7cb36a00 --- /dev/null +++ b/crates/typst-eval/src/methods.rs @@ -0,0 +1,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}`") +} |
