summaryrefslogtreecommitdiff
path: root/src/model
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-12-30 19:40:29 +0100
committerLaurenz <laurmaedje@gmail.com>2022-12-30 20:00:50 +0100
commita6d90c1bf1e9fefa0af04206909a40e112d6bb14 (patch)
treefc16276142f74b9a50102a2e855942f7e2593c25 /src/model
parentf70cea508cd30fa40770ea989fe2a19e715a357b (diff)
Numbering functions
Diffstat (limited to 'src/model')
-rw-r--r--src/model/args.rs2
-rw-r--r--src/model/array.rs77
-rw-r--r--src/model/dict.rs12
-rw-r--r--src/model/eval.rs14
-rw-r--r--src/model/func.rs50
-rw-r--r--src/model/methods.rs2
-rw-r--r--src/model/realize.rs7
7 files changed, 96 insertions, 68 deletions
diff --git a/src/model/args.rs b/src/model/args.rs
index 4aaaded4..9ab07ed8 100644
--- a/src/model/args.rs
+++ b/src/model/args.rs
@@ -150,7 +150,7 @@ impl Args {
}
/// Extract the positional arguments as an array.
- pub fn to_positional(&self) -> Array {
+ pub fn to_pos(&self) -> Array {
self.items
.iter()
.filter(|item| item.name.is_none())
diff --git a/src/model/array.rs b/src/model/array.rs
index fb740a13..28b9d1a0 100644
--- a/src/model/array.rs
+++ b/src/model/array.rs
@@ -5,7 +5,6 @@ use std::sync::Arc;
use super::{ops, Args, Func, Value, Vm};
use crate::diag::{bail, At, SourceResult, StrResult};
-use crate::syntax::Spanned;
use crate::util::{format_eco, ArcExt, EcoString};
/// Create a new [`Array`] from values.
@@ -137,13 +136,13 @@ impl Array {
}
/// Return the first matching element.
- pub fn find(&self, vm: &Vm, f: Spanned<Func>) -> SourceResult<Option<Value>> {
- if f.v.argc().map_or(false, |count| count != 1) {
- bail!(f.span, "function must have exactly one parameter");
+ pub fn find(&self, vm: &Vm, func: Func) -> SourceResult<Option<Value>> {
+ if func.argc().map_or(false, |count| count != 1) {
+ bail!(func.span(), "function must have exactly one parameter");
}
for item in self.iter() {
- let args = Args::new(f.span, [item.clone()]);
- if f.v.call(vm, args)?.cast::<bool>().at(f.span)? {
+ let args = Args::new(func.span(), [item.clone()]);
+ if func.call(vm, args)?.cast::<bool>().at(func.span())? {
return Ok(Some(item.clone()));
}
}
@@ -152,13 +151,13 @@ impl Array {
}
/// Return the index of the first matching element.
- pub fn position(&self, vm: &Vm, f: Spanned<Func>) -> SourceResult<Option<i64>> {
- if f.v.argc().map_or(false, |count| count != 1) {
- bail!(f.span, "function must have exactly one parameter");
+ pub fn position(&self, vm: &Vm, func: Func) -> SourceResult<Option<i64>> {
+ if func.argc().map_or(false, |count| count != 1) {
+ bail!(func.span(), "function must have exactly one parameter");
}
for (i, item) in self.iter().enumerate() {
- let args = Args::new(f.span, [item.clone()]);
- if f.v.call(vm, args)?.cast::<bool>().at(f.span)? {
+ let args = Args::new(func.span(), [item.clone()]);
+ if func.call(vm, args)?.cast::<bool>().at(func.span())? {
return Ok(Some(i as i64));
}
}
@@ -168,14 +167,14 @@ impl Array {
/// Return a new array with only those elements for which the function
/// returns true.
- pub fn filter(&self, vm: &Vm, f: Spanned<Func>) -> SourceResult<Self> {
- if f.v.argc().map_or(false, |count| count != 1) {
- bail!(f.span, "function must have exactly one parameter");
+ pub fn filter(&self, vm: &Vm, func: Func) -> SourceResult<Self> {
+ if func.argc().map_or(false, |count| count != 1) {
+ bail!(func.span(), "function must have exactly one parameter");
}
let mut kept = vec![];
for item in self.iter() {
- let args = Args::new(f.span, [item.clone()]);
- if f.v.call(vm, args)?.cast::<bool>().at(f.span)? {
+ let args = Args::new(func.span(), [item.clone()]);
+ if func.call(vm, args)?.cast::<bool>().at(func.span())? {
kept.push(item.clone())
}
}
@@ -183,45 +182,45 @@ impl Array {
}
/// Transform each item in the array with a function.
- pub fn map(&self, vm: &Vm, f: Spanned<Func>) -> SourceResult<Self> {
- if f.v.argc().map_or(false, |count| count < 1 || count > 2) {
- bail!(f.span, "function must have one or two parameters");
+ pub fn map(&self, vm: &Vm, func: Func) -> SourceResult<Self> {
+ if func.argc().map_or(false, |count| count < 1 || count > 2) {
+ bail!(func.span(), "function must have one or two parameters");
}
- let enumerate = f.v.argc() == Some(2);
+ let enumerate = func.argc() == Some(2);
self.iter()
.enumerate()
.map(|(i, item)| {
- let mut args = Args::new(f.span, []);
+ let mut args = Args::new(func.span(), []);
if enumerate {
- args.push(f.span, Value::Int(i as i64));
+ args.push(func.span(), Value::Int(i as i64));
}
- args.push(f.span, item.clone());
- f.v.call(vm, args)
+ args.push(func.span(), item.clone());
+ func.call(vm, args)
})
.collect()
}
/// Fold all of the array's elements into one with a function.
- pub fn fold(&self, vm: &Vm, init: Value, f: Spanned<Func>) -> SourceResult<Value> {
- if f.v.argc().map_or(false, |count| count != 2) {
- bail!(f.span, "function must have exactly two parameters");
+ pub fn fold(&self, vm: &Vm, init: Value, func: Func) -> SourceResult<Value> {
+ if func.argc().map_or(false, |count| count != 2) {
+ bail!(func.span(), "function must have exactly two parameters");
}
let mut acc = init;
for item in self.iter() {
- let args = Args::new(f.span, [acc, item.clone()]);
- acc = f.v.call(vm, args)?;
+ let args = Args::new(func.span(), [acc, item.clone()]);
+ acc = func.call(vm, args)?;
}
Ok(acc)
}
/// Whether any element matches.
- pub fn any(&self, vm: &Vm, f: Spanned<Func>) -> SourceResult<bool> {
- if f.v.argc().map_or(false, |count| count != 1) {
- bail!(f.span, "function must have exactly one parameter");
+ pub fn any(&self, vm: &Vm, func: Func) -> SourceResult<bool> {
+ if func.argc().map_or(false, |count| count != 1) {
+ bail!(func.span(), "function must have exactly one parameter");
}
for item in self.iter() {
- let args = Args::new(f.span, [item.clone()]);
- if f.v.call(vm, args)?.cast::<bool>().at(f.span)? {
+ let args = Args::new(func.span(), [item.clone()]);
+ if func.call(vm, args)?.cast::<bool>().at(func.span())? {
return Ok(true);
}
}
@@ -230,13 +229,13 @@ impl Array {
}
/// Whether all elements match.
- pub fn all(&self, vm: &Vm, f: Spanned<Func>) -> SourceResult<bool> {
- if f.v.argc().map_or(false, |count| count != 1) {
- bail!(f.span, "function must have exactly one parameter");
+ pub fn all(&self, vm: &Vm, func: Func) -> SourceResult<bool> {
+ if func.argc().map_or(false, |count| count != 1) {
+ bail!(func.span(), "function must have exactly one parameter");
}
for item in self.iter() {
- let args = Args::new(f.span, [item.clone()]);
- if !f.v.call(vm, args)?.cast::<bool>().at(f.span)? {
+ let args = Args::new(func.span(), [item.clone()]);
+ if !func.call(vm, args)?.cast::<bool>().at(func.span())? {
return Ok(false);
}
}
diff --git a/src/model/dict.rs b/src/model/dict.rs
index 83c16824..a5dbeeae 100644
--- a/src/model/dict.rs
+++ b/src/model/dict.rs
@@ -6,7 +6,6 @@ use std::sync::Arc;
use super::{Args, Array, Func, Str, Value, Vm};
use crate::diag::{bail, SourceResult, StrResult};
use crate::syntax::is_ident;
-use crate::syntax::Spanned;
use crate::util::{format_eco, ArcExt, EcoString};
/// Create a new [`Dict`] from key-value pairs.
@@ -107,14 +106,15 @@ impl Dict {
}
/// Transform each pair in the dictionary with a function.
- pub fn map(&self, vm: &Vm, f: Spanned<Func>) -> SourceResult<Array> {
- if f.v.argc().map_or(false, |count| count != 1) {
- bail!(f.span, "function must have exactly two parameters");
+ pub fn map(&self, vm: &Vm, func: Func) -> SourceResult<Array> {
+ if func.argc().map_or(false, |count| count != 2) {
+ bail!(func.span(), "function must have exactly two parameters");
}
self.iter()
.map(|(key, value)| {
- let args = Args::new(f.span, [Value::Str(key.clone()), value.clone()]);
- f.v.call(vm, args)
+ let args =
+ Args::new(func.span(), [Value::Str(key.clone()), value.clone()]);
+ func.call(vm, args)
})
.collect()
}
diff --git a/src/model/eval.rs b/src/model/eval.rs
index ab89f9c2..e9134114 100644
--- a/src/model/eval.rs
+++ b/src/model/eval.rs
@@ -563,7 +563,11 @@ impl Eval for ast::Ident {
type Output = Value;
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
- vm.scopes.get(self).cloned().at(self.span())
+ let value = vm.scopes.get(self).cloned().at(self.span())?;
+ Ok(match value {
+ Value::Func(func) => Value::Func(func.spanned(self.span())),
+ value => value,
+ })
}
}
@@ -912,15 +916,17 @@ impl Eval for ast::Closure {
}
}
- // Define the actual function.
- Ok(Value::Func(Func::from_closure(Closure {
+ // Define the closure function.
+ let closure = Closure {
location: vm.location,
name,
captured,
params,
sink,
body: self.body(),
- })))
+ };
+
+ Ok(Value::Func(Func::from_closure(closure, self.span())))
}
}
diff --git a/src/model/func.rs b/src/model/func.rs
index 3fb8f4d4..878b717f 100644
--- a/src/model/func.rs
+++ b/src/model/func.rs
@@ -10,13 +10,13 @@ use super::{
};
use crate::diag::{bail, SourceResult, StrResult};
use crate::syntax::ast::{self, AstNode, Expr};
-use crate::syntax::{SourceId, SyntaxNode};
+use crate::syntax::{SourceId, Span, SyntaxNode};
use crate::util::EcoString;
use crate::World;
/// An evaluatable function.
#[derive(Clone, Hash)]
-pub struct Func(Arc<Repr>);
+pub struct Func(Arc<Repr>, Span);
/// The different kinds of function representations.
#[derive(Hash)]
@@ -40,27 +40,33 @@ impl Func {
func: fn(&Vm, &mut Args) -> SourceResult<Value>,
info: FuncInfo,
) -> Self {
- Self(Arc::new(Repr::Native(Native { func, set: None, node: None, info })))
+ Self(
+ Arc::new(Repr::Native(Native { func, set: None, node: None, info })),
+ Span::detached(),
+ )
}
/// Create a new function from a native rust node.
pub fn from_node<T: Node>(mut info: FuncInfo) -> Self {
info.params.extend(T::properties());
- Self(Arc::new(Repr::Native(Native {
- func: |ctx, args| {
- let styles = T::set(args, true)?;
- let content = T::construct(ctx, args)?;
- Ok(Value::Content(content.styled_with_map(styles.scoped())))
- },
- set: Some(|args| T::set(args, false)),
- node: Some(NodeId::of::<T>()),
- info,
- })))
+ Self(
+ Arc::new(Repr::Native(Native {
+ func: |ctx, args| {
+ let styles = T::set(args, true)?;
+ let content = T::construct(ctx, args)?;
+ Ok(Value::Content(content.styled_with_map(styles.scoped())))
+ },
+ set: Some(|args| T::set(args, false)),
+ node: Some(NodeId::of::<T>()),
+ info,
+ })),
+ Span::detached(),
+ )
}
/// Create a new function from a closure.
- pub(super) fn from_closure(closure: Closure) -> Self {
- Self(Arc::new(Repr::Closure(closure)))
+ pub(super) fn from_closure(closure: Closure, span: Span) -> Self {
+ Self(Arc::new(Repr::Closure(closure)), span)
}
/// The name of the function.
@@ -81,6 +87,17 @@ impl Func {
}
}
+ /// The function's span.
+ pub fn span(&self) -> Span {
+ self.1
+ }
+
+ /// Attach a span to the function.
+ pub fn spanned(mut self, span: Span) -> Self {
+ self.1 = span;
+ self
+ }
+
/// The number of positional arguments this function takes, if known.
pub fn argc(&self) -> Option<usize> {
match self.0.as_ref() {
@@ -121,7 +138,8 @@ impl Func {
/// Apply the given arguments to the function.
pub fn with(self, args: Args) -> Self {
- Self(Arc::new(Repr::With(self, args)))
+ let span = self.1;
+ Self(Arc::new(Repr::With(self, args)), span)
}
/// Create a selector for this function's node type, filtering by node's
diff --git a/src/model/methods.rs b/src/model/methods.rs
index 8155685c..3823df41 100644
--- a/src/model/methods.rs
+++ b/src/model/methods.rs
@@ -118,7 +118,7 @@ pub fn call(
},
Value::Args(args) => match method {
- "positional" => Value::Array(args.to_positional()),
+ "pos" => Value::Array(args.to_pos()),
"named" => Value::Dict(args.to_named()),
_ => return missing(),
},
diff --git a/src/model/realize.rs b/src/model/realize.rs
index 862bc8b6..39c1fd42 100644
--- a/src/model/realize.rs
+++ b/src/model/realize.rs
@@ -136,7 +136,12 @@ fn try_apply(
#[capability]
pub trait Prepare {
/// Prepare the node for show rule application.
- fn prepare(&self, vt: &mut Vt, this: Content, styles: StyleChain) -> Content;
+ fn prepare(
+ &self,
+ vt: &mut Vt,
+ this: Content,
+ styles: StyleChain,
+ ) -> SourceResult<Content>;
}
/// The base recipe for a node.