From e4ee14e54fb87961096856c7ea105435b7cc3c45 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Sun, 24 Apr 2022 15:27:06 +0200 Subject: [PATCH] Extract methods into separate module --- src/eval/methods.rs | 119 ++++++++++++++++++++++++++++++++++++++++++ src/eval/mod.rs | 13 ++--- src/eval/ops.rs | 2 + src/eval/value.rs | 123 ++------------------------------------------ 4 files changed, 131 insertions(+), 126 deletions(-) create mode 100644 src/eval/methods.rs diff --git a/src/eval/methods.rs b/src/eval/methods.rs new file mode 100644 index 000000000..017591b44 --- /dev/null +++ b/src/eval/methods.rs @@ -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 { + 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}`") +} diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 7e0d3b15d..f77efe47a 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -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)? }) } } diff --git a/src/eval/ops.rs b/src/eval/ops.rs index 4796e042e..703520395 100644 --- a/src/eval/ops.rs +++ b/src/eval/ops.rs @@ -1,3 +1,5 @@ +//! Operations on values. + use std::cmp::Ordering; use super::{Dynamic, RawAlign, RawStroke, Smart, StrExt, Value}; diff --git a/src/eval/value.rs b/src/eval/value.rs index cc312c5a6..2ef260590 100644 --- a/src/eval/value.rs +++ b/src/eval/value.rs @@ -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 { - 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 {