Enable for loop over captured args

This commit is contained in:
Laurenz 2022-01-29 21:36:25 +01:00
parent 3cad6bf607
commit 24d513d891
4 changed files with 25 additions and 17 deletions

View File

@ -642,16 +642,8 @@ impl Eval for CallArgs {
value: Spanned::new(value, span),
}));
}
v => {
if let Value::Dyn(dynamic) = &v {
if let Some(args) = dynamic.downcast::<Args>() {
items.extend(args.items.iter().cloned());
continue;
}
}
bail!(expr.span(), "cannot spread {}", v.type_name())
}
Value::Args(args) => items.extend(args.items),
v => bail!(expr.span(), "cannot spread {}", v.type_name()),
},
}
}
@ -716,10 +708,6 @@ impl Eval for ClosureExpr {
// Put the remaining arguments into the sink.
if let Some(sink) = &sink {
dynamic! {
Args: "arguments",
}
ctx.scopes.def_mut(sink, args.take());
}
@ -868,6 +856,15 @@ impl Eval for ForExpr {
(Some(k), v, Value::Dict(dict)) => {
iter!(for (k => key, v => value) in dict.into_iter());
}
(None, v, Value::Args(args)) => {
iter!(for (v => value) in args.items.into_iter()
.filter(|arg| arg.name.is_none())
.map(|arg| arg.value.v));
}
(Some(k), v, Value::Args(args)) => {
iter!(for (k => key, v => value) in args.items.into_iter()
.map(|arg| (arg.name.map_or(Value::None, Value::Str), arg.value.v)));
}
(_, _, Value::Str(_)) => {
bail!(pattern.span(), "mismatched pattern");
}

View File

@ -4,7 +4,7 @@ use std::fmt::{self, Debug, Formatter};
use std::hash::Hash;
use std::rc::Rc;
use super::{ops, Array, Class, Dict, Function, Node};
use super::{ops, Args, Array, Class, Dict, Function, Node};
use crate::diag::StrResult;
use crate::geom::{Angle, Color, Fractional, Length, Linear, Relative, RgbaColor};
use crate::layout::Layout;
@ -46,6 +46,8 @@ pub enum Value {
Node(Node),
/// An executable function.
Func(Function),
/// Captured arguments to a function.
Args(Args),
/// A class of nodes.
Class(Class),
/// A dynamic value.
@ -88,6 +90,7 @@ impl Value {
Self::Dict(_) => Dict::TYPE_NAME,
Self::Node(_) => Node::TYPE_NAME,
Self::Func(_) => Function::TYPE_NAME,
Self::Args(_) => Args::TYPE_NAME,
Self::Class(_) => Class::TYPE_NAME,
Self::Dyn(v) => v.type_name(),
}
@ -151,6 +154,7 @@ impl Debug for Value {
Self::Dict(v) => Debug::fmt(v, f),
Self::Node(_) => f.pad("<template>"),
Self::Func(v) => Debug::fmt(v, f),
Self::Args(v) => Debug::fmt(v, f),
Self::Class(v) => Debug::fmt(v, f),
Self::Dyn(v) => Debug::fmt(v, f),
}
@ -219,12 +223,12 @@ impl Dynamic {
}
/// Whether the wrapped type is `T`.
pub fn is<T: 'static>(&self) -> bool {
pub fn is<T: Type + 'static>(&self) -> bool {
self.0.as_any().is::<T>()
}
/// Try to downcast to a reference to a specific type.
pub fn downcast<T: 'static>(&self) -> Option<&T> {
pub fn downcast<T: Type + 'static>(&self) -> Option<&T> {
self.0.as_any().downcast_ref()
}
@ -404,6 +408,7 @@ primitive! { Function: "function",
move |ctx, args| v.construct(ctx, args).map(Value::Node)
)
}
primitive! { Args: "arguments", Args }
primitive! { Class: "class", Class }
impl Cast<Value> for Value {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -32,6 +32,12 @@
// Should output `2345`.
#for v in (1, 2, 3, 4, 5, 6, 7) [#if v >= 2 and v <= 5 { repr(v) }]
// Loop over captured arguments.
#let f1(..args) = for v in args { (repr(v),) }
#let f2(..args) = for k, v in args { (repr(k) + ": " + repr(v),) }
#let f(..args) = join(sep: ", ", ..f1(..args), ..f2(..args))
#f(1, a: 2)
---
#let out = ()