From 88e50a55afff7b809d4b9d6cfaf93275bfe06f56 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Wed, 2 Feb 2022 16:32:30 +0100 Subject: [PATCH] Pass arguments to call and construct directly by value --- src/eval/class.rs | 45 +++++++++++++++++++++++++-------------------- src/eval/func.rs | 14 ++++++++------ src/eval/mod.rs | 16 +++++----------- 3 files changed, 38 insertions(+), 37 deletions(-) diff --git a/src/eval/class.rs b/src/eval/class.rs index 4307eecbd..acdf38e6f 100644 --- a/src/eval/class.rs +++ b/src/eval/class.rs @@ -6,15 +6,15 @@ use crate::diag::TypResult; /// A class of nodes. /// /// You can [construct] an instance of a class in Typst code by invoking the -/// class as a callable. This always produces a template, but not necessarily a -/// simple inline or block node. For example, the `text` constructor does not -/// actually create a [`TextNode`]. Instead it applies styling to whatever node -/// you pass in and returns it structurally unchanged. +/// class as a callable. This always produces a template value, but not +/// necessarily a simple inline or block node. For example, the `text` +/// constructor does not actually create a [`TextNode`]. Instead it applies +/// styling to whatever node you pass in and returns it structurally unchanged. /// /// The arguments you can pass to a class constructor fall into two categories: -/// Data that is inherent to the instance (e.g. the text of a heading) and style -/// properties (e.g. the fill color of a heading). As the latter are often -/// shared by many instances throughout a document, they can also be +/// Data that is inherent to the instance (e.g. the text/content of a heading) +/// and style properties (e.g. the fill color of a heading). As the latter are +/// often shared by many instances throughout a document, they can also be /// conveniently configured through class's [`set`] rule. Then, they apply to /// all nodes that are instantiated into the template where the `set` was /// executed. @@ -62,25 +62,30 @@ impl Class { self.name } + /// Return the class constructor as a function. + pub fn constructor(&self) -> Func { + Func::native(self.name, self.construct) + } + /// Construct an instance of the class. /// - /// This parses both property and data arguments (in this order) and styles - /// the template constructed from the data with the style properties. - pub fn construct(&self, ctx: &mut EvalContext, args: &mut Args) -> TypResult { - (self.construct)(ctx, args) + /// This parses both property and data arguments (in this order), styles the + /// template constructed from the data with the style properties and wraps + /// it in a value. + pub fn construct(&self, ctx: &mut EvalContext, mut args: Args) -> TypResult { + let value = (self.construct)(ctx, &mut args)?; + args.finish()?; + Ok(value) } /// Execute the class's set rule. /// - /// This parses property arguments and writes the resulting styles into the - /// given style map. There are no further side effects. - pub fn set(&self, args: &mut Args, styles: &mut StyleMap) -> TypResult<()> { - (self.set)(args, styles) - } - - /// Return the class constructor as a function. - pub fn constructor(&self) -> Func { - Func::native(self.name, self.construct) + /// This parses property arguments and return the resulting styles. + pub fn set(&self, mut args: Args) -> TypResult { + let mut styles = StyleMap::new(); + (self.set)(&mut args, &mut styles)?; + args.finish()?; + Ok(styles) } } diff --git a/src/eval/func.rs b/src/eval/func.rs index ccd0932f2..6d405ca43 100644 --- a/src/eval/func.rs +++ b/src/eval/func.rs @@ -45,15 +45,17 @@ impl Func { } /// Call the function in the context with the arguments. - pub fn call(&self, ctx: &mut EvalContext, args: &mut Args) -> TypResult { - match self.0.as_ref() { - Repr::Native(native) => (native.func)(ctx, args), - Repr::Closure(closure) => closure.call(ctx, args), + pub fn call(&self, ctx: &mut EvalContext, mut args: Args) -> TypResult { + let value = match self.0.as_ref() { + Repr::Native(native) => (native.func)(ctx, &mut args)?, + Repr::Closure(closure) => closure.call(ctx, &mut args)?, Repr::With(wrapped, applied) => { args.items.splice(.. 0, applied.items.iter().cloned()); - wrapped.call(ctx, args) + return wrapped.call(ctx, args); } - } + }; + args.finish()?; + Ok(value) } /// Apply the given arguments to the function. diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 33ee23ca4..7c038c2a4 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -189,10 +189,8 @@ fn eval_markup( MarkupNode::Expr(Expr::Set(set)) => { let class = set.class(); let class = class.eval(ctx)?.cast::().at(class.span())?; - let mut args = set.args().eval(ctx)?; - let mut styles = StyleMap::new(); - class.set(&mut args, &mut styles)?; - args.finish()?; + let args = set.args().eval(ctx)?; + let styles = class.set(args)?; let tail = eval_markup(ctx, nodes)?; tail.styled_with_map(styles) } @@ -590,7 +588,7 @@ impl Eval for CallExpr { fn eval(&self, ctx: &mut EvalContext) -> TypResult { let span = self.callee().span(); let callee = self.callee().eval(ctx)?; - let mut args = self.args().eval(ctx)?; + let args = self.args().eval(ctx)?; match callee { Value::Array(array) => { @@ -603,16 +601,12 @@ impl Eval for CallExpr { Value::Func(func) => { let point = || Tracepoint::Call(func.name().map(ToString::to_string)); - let value = func.call(ctx, &mut args).trace(point, self.span())?; - args.finish()?; - Ok(value) + func.call(ctx, args).trace(point, self.span()) } Value::Class(class) => { let point = || Tracepoint::Call(Some(class.name().to_string())); - let value = class.construct(ctx, &mut args).trace(point, self.span())?; - args.finish()?; - Ok(value) + class.construct(ctx, args).trace(point, self.span()) } v => bail!(