Extract methods into separate module
This commit is contained in:
parent
50e4002a2a
commit
e4ee14e54f
119
src/eval/methods.rs
Normal file
119
src/eval/methods.rs
Normal file
@ -0,0 +1,119 @@
|
||||
//! Methods on values.
|
||||
|
||||
use super::{Args, StrExt, Value};
|
||||
use crate::diag::{At, TypResult};
|
||||
use crate::syntax::Span;
|
||||
use crate::Context;
|
||||
|
||||
/// Call a method on a value.
|
||||
pub fn call(
|
||||
ctx: &mut Context,
|
||||
value: Value,
|
||||
method: &str,
|
||||
mut args: Args,
|
||||
span: Span,
|
||||
) -> TypResult<Value> {
|
||||
let name = value.type_name();
|
||||
let missing = || Err(missing_method(name, method)).at(span);
|
||||
|
||||
let output = match value {
|
||||
Value::Str(string) => match method {
|
||||
"len" => Value::Int(string.len() as i64),
|
||||
"trim" => Value::Str(string.trim().into()),
|
||||
"split" => Value::Array(string.split(args.eat()?)),
|
||||
_ => missing()?,
|
||||
},
|
||||
|
||||
Value::Array(array) => match method {
|
||||
"len" => Value::Int(array.len()),
|
||||
"slice" => {
|
||||
let start = args.expect("start")?;
|
||||
let mut end = args.eat()?;
|
||||
if end.is_none() {
|
||||
end = args.named("count")?.map(|c: i64| start + c);
|
||||
}
|
||||
Value::Array(array.slice(start, end).at(span)?)
|
||||
}
|
||||
"map" => Value::Array(array.map(ctx, args.expect("function")?)?),
|
||||
"filter" => Value::Array(array.filter(ctx, args.expect("function")?)?),
|
||||
"flatten" => Value::Array(array.flatten()),
|
||||
"find" => array.find(args.expect("value")?).map_or(Value::None, Value::Int),
|
||||
"join" => {
|
||||
let sep = args.eat()?;
|
||||
let last = args.named("last")?;
|
||||
array.join(sep, last).at(span)?
|
||||
}
|
||||
"sorted" => Value::Array(array.sorted().at(span)?),
|
||||
_ => missing()?,
|
||||
},
|
||||
|
||||
Value::Dict(dict) => match method {
|
||||
"len" => Value::Int(dict.len()),
|
||||
"keys" => Value::Array(dict.keys()),
|
||||
"values" => Value::Array(dict.values()),
|
||||
"pairs" => Value::Array(dict.map(ctx, args.expect("function")?)?),
|
||||
_ => missing()?,
|
||||
},
|
||||
|
||||
Value::Func(func) => match method {
|
||||
"with" => Value::Func(func.clone().with(args.take())),
|
||||
_ => missing()?,
|
||||
},
|
||||
|
||||
Value::Args(args) => match method {
|
||||
"positional" => Value::Array(args.to_positional()),
|
||||
"named" => Value::Dict(args.to_named()),
|
||||
_ => missing()?,
|
||||
},
|
||||
|
||||
_ => missing()?,
|
||||
};
|
||||
|
||||
args.finish()?;
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
/// Call a mutating method on a value.
|
||||
pub fn call_mut(
|
||||
_: &mut Context,
|
||||
value: &mut Value,
|
||||
method: &str,
|
||||
mut args: Args,
|
||||
span: Span,
|
||||
) -> TypResult<()> {
|
||||
let name = value.type_name();
|
||||
let missing = || Err(missing_method(name, method)).at(span);
|
||||
|
||||
match value {
|
||||
Value::Array(array) => match method {
|
||||
"push" => array.push(args.expect("value")?),
|
||||
"pop" => array.pop().at(span)?,
|
||||
"insert" => {
|
||||
array.insert(args.expect("index")?, args.expect("value")?).at(span)?
|
||||
}
|
||||
"remove" => array.remove(args.expect("index")?).at(span)?,
|
||||
_ => missing()?,
|
||||
},
|
||||
|
||||
Value::Dict(dict) => match method {
|
||||
"remove" => dict.remove(args.expect("key")?).at(span)?,
|
||||
_ => missing()?,
|
||||
},
|
||||
|
||||
_ => missing()?,
|
||||
}
|
||||
|
||||
args.finish()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Whether a specific method is mutating.
|
||||
pub fn is_mutating(method: &str) -> bool {
|
||||
matches!(method, "push" | "pop" | "insert" | "remove")
|
||||
}
|
||||
|
||||
/// The missing method error message.
|
||||
#[cold]
|
||||
fn missing_method(type_name: &str, method: &str) -> String {
|
||||
format!("type {type_name} has no method `{method}`")
|
||||
}
|
@ -15,8 +15,9 @@ mod content;
|
||||
mod control;
|
||||
mod func;
|
||||
mod layout;
|
||||
pub mod methods;
|
||||
mod module;
|
||||
mod ops;
|
||||
pub mod ops;
|
||||
mod raw;
|
||||
mod scope;
|
||||
mod show;
|
||||
@ -484,15 +485,15 @@ impl Eval for MethodCall {
|
||||
let method = self.method();
|
||||
let point = || Tracepoint::Call(Some(method.to_string()));
|
||||
|
||||
Ok(if Value::is_mutable_method(&method) {
|
||||
Ok(if methods::is_mutating(&method) {
|
||||
let args = self.args().eval(ctx, scp)?;
|
||||
let mut receiver = self.receiver().access(ctx, scp)?;
|
||||
receiver.call_mut(ctx, &method, span, args).trace(point, span)?;
|
||||
let mut value = self.receiver().access(ctx, scp)?;
|
||||
methods::call_mut(ctx, &mut value, &method, args, span).trace(point, span)?;
|
||||
Value::None
|
||||
} else {
|
||||
let receiver = self.receiver().eval(ctx, scp)?;
|
||||
let value = self.receiver().eval(ctx, scp)?;
|
||||
let args = self.args().eval(ctx, scp)?;
|
||||
receiver.call(ctx, &method, span, args).trace(point, span)?
|
||||
methods::call(ctx, value, &method, args, span).trace(point, span)?
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
//! Operations on values.
|
||||
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use super::{Dynamic, RawAlign, RawStroke, Smart, StrExt, Value};
|
||||
|
@ -5,15 +5,13 @@ use std::hash::{Hash, Hasher};
|
||||
use std::num::NonZeroUsize;
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::{
|
||||
ops, Args, Array, Content, Context, Dict, Func, Layout, LayoutNode, RawLength, StrExt,
|
||||
};
|
||||
use crate::diag::{with_alternative, At, StrResult, TypResult};
|
||||
use super::{ops, Args, Array, Content, Dict, Func, Layout, LayoutNode, RawLength};
|
||||
use crate::diag::{with_alternative, StrResult};
|
||||
use crate::geom::{
|
||||
Angle, Color, Dir, Em, Fraction, Length, Paint, Ratio, Relative, RgbaColor,
|
||||
};
|
||||
use crate::library::text::RawNode;
|
||||
use crate::syntax::{Span, Spanned};
|
||||
use crate::syntax::Spanned;
|
||||
use crate::util::EcoString;
|
||||
|
||||
/// A computational value.
|
||||
@ -127,121 +125,6 @@ impl Value {
|
||||
v => Content::show(RawNode { text: v.repr(), block: false }),
|
||||
}
|
||||
}
|
||||
|
||||
/// Call a method on the value.
|
||||
pub fn call(
|
||||
&self,
|
||||
ctx: &mut Context,
|
||||
method: &str,
|
||||
span: Span,
|
||||
mut args: Args,
|
||||
) -> TypResult<Self> {
|
||||
let name = self.type_name();
|
||||
let missing = || Err(missing_method(name, method)).at(span);
|
||||
|
||||
let output = match self {
|
||||
Value::Str(string) => match method {
|
||||
"len" => Value::Int(string.len() as i64),
|
||||
"trim" => Value::Str(string.trim().into()),
|
||||
"split" => Value::Array(string.split(args.eat()?)),
|
||||
_ => missing()?,
|
||||
},
|
||||
|
||||
Value::Array(array) => match method {
|
||||
"len" => Value::Int(array.len()),
|
||||
"slice" => {
|
||||
let start = args.expect("start")?;
|
||||
let mut end = args.eat()?;
|
||||
if end.is_none() {
|
||||
end = args.named("count")?.map(|c: i64| start + c);
|
||||
}
|
||||
Value::Array(array.slice(start, end).at(span)?)
|
||||
}
|
||||
"map" => Value::Array(array.map(ctx, args.expect("function")?)?),
|
||||
"filter" => Value::Array(array.filter(ctx, args.expect("function")?)?),
|
||||
"flatten" => Value::Array(array.flatten()),
|
||||
"find" => {
|
||||
array.find(args.expect("value")?).map_or(Value::None, Value::Int)
|
||||
}
|
||||
"join" => {
|
||||
let sep = args.eat()?;
|
||||
let last = args.named("last")?;
|
||||
array.join(sep, last).at(span)?
|
||||
}
|
||||
"sorted" => Value::Array(array.sorted().at(span)?),
|
||||
_ => missing()?,
|
||||
},
|
||||
|
||||
Value::Dict(dict) => match method {
|
||||
"len" => Value::Int(dict.len()),
|
||||
"keys" => Value::Array(dict.keys()),
|
||||
"values" => Value::Array(dict.values()),
|
||||
"pairs" => Value::Array(dict.map(ctx, args.expect("function")?)?),
|
||||
_ => missing()?,
|
||||
},
|
||||
|
||||
Value::Func(func) => match method {
|
||||
"with" => Value::Func(func.clone().with(args.take())),
|
||||
_ => missing()?,
|
||||
},
|
||||
|
||||
Value::Args(args) => match method {
|
||||
"positional" => Value::Array(args.to_positional()),
|
||||
"named" => Value::Dict(args.to_named()),
|
||||
_ => missing()?,
|
||||
},
|
||||
|
||||
_ => missing()?,
|
||||
};
|
||||
|
||||
args.finish()?;
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
/// Call a mutating method on the value.
|
||||
pub fn call_mut(
|
||||
&mut self,
|
||||
_: &mut Context,
|
||||
method: &str,
|
||||
span: Span,
|
||||
mut args: Args,
|
||||
) -> TypResult<()> {
|
||||
let name = self.type_name();
|
||||
let missing = || Err(missing_method(name, method)).at(span);
|
||||
|
||||
match self {
|
||||
Value::Array(array) => match method {
|
||||
"push" => array.push(args.expect("value")?),
|
||||
"pop" => array.pop().at(span)?,
|
||||
"insert" => {
|
||||
array.insert(args.expect("index")?, args.expect("value")?).at(span)?
|
||||
}
|
||||
"remove" => array.remove(args.expect("index")?).at(span)?,
|
||||
_ => missing()?,
|
||||
},
|
||||
|
||||
Value::Dict(dict) => match method {
|
||||
"remove" => dict.remove(args.expect("key")?).at(span)?,
|
||||
_ => missing()?,
|
||||
},
|
||||
|
||||
_ => missing()?,
|
||||
}
|
||||
|
||||
args.finish()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Whether a specific method is mutable.
|
||||
pub fn is_mutable_method(method: &str) -> bool {
|
||||
matches!(method, "push" | "pop" | "insert" | "remove")
|
||||
}
|
||||
}
|
||||
|
||||
/// The missing method error message.
|
||||
#[cold]
|
||||
fn missing_method(type_name: &str, method: &str) -> String {
|
||||
format!("type {type_name} has no method `{method}`")
|
||||
}
|
||||
|
||||
impl Default for Value {
|
||||
|
Loading…
x
Reference in New Issue
Block a user