summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-04-24 15:27:06 +0200
committerLaurenz <laurmaedje@gmail.com>2022-04-24 15:27:06 +0200
commite4ee14e54fb87961096856c7ea105435b7cc3c45 (patch)
tree3430a5e257920bb776e734b28edda29019d899e2 /src
parent50e4002a2a65c27f46895103c59cb775ca60d16d (diff)
Extract methods into separate module
Diffstat (limited to 'src')
-rw-r--r--src/eval/methods.rs119
-rw-r--r--src/eval/mod.rs13
-rw-r--r--src/eval/ops.rs2
-rw-r--r--src/eval/value.rs123
4 files changed, 131 insertions, 126 deletions
diff --git a/src/eval/methods.rs b/src/eval/methods.rs
new file mode 100644
index 00000000..017591b4
--- /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<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}`")
+}
diff --git a/src/eval/mod.rs b/src/eval/mod.rs
index 7e0d3b15..f77efe47 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 4796e042..70352039 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 cc312c5a..2ef26059 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<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 {