diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-12-30 19:40:29 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-12-30 20:00:50 +0100 |
| commit | a6d90c1bf1e9fefa0af04206909a40e112d6bb14 (patch) | |
| tree | fc16276142f74b9a50102a2e855942f7e2593c25 /src | |
| parent | f70cea508cd30fa40770ea989fe2a19e715a357b (diff) | |
Numbering functions
Diffstat (limited to 'src')
| -rw-r--r-- | src/diag.rs | 2 | ||||
| -rw-r--r-- | src/model/args.rs | 2 | ||||
| -rw-r--r-- | src/model/array.rs | 77 | ||||
| -rw-r--r-- | src/model/dict.rs | 12 | ||||
| -rw-r--r-- | src/model/eval.rs | 14 | ||||
| -rw-r--r-- | src/model/func.rs | 50 | ||||
| -rw-r--r-- | src/model/methods.rs | 2 | ||||
| -rw-r--r-- | src/model/realize.rs | 7 |
8 files changed, 98 insertions, 68 deletions
diff --git a/src/diag.rs b/src/diag.rs index 55f16b5f..e0015fcc 100644 --- a/src/diag.rs +++ b/src/diag.rs @@ -66,7 +66,9 @@ pub struct SourceError { impl SourceError { /// Create a new, bare error. + #[track_caller] pub fn new(span: Span, message: impl Into<EcoString>) -> Self { + assert!(!span.is_detached()); Self { span, pos: ErrorPos::Full, 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. |
