summaryrefslogtreecommitdiff
path: root/src/eval/mod.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-01-26 23:30:03 +0100
committerLaurenz <laurmaedje@gmail.com>2021-01-26 23:30:03 +0100
commit710f88ccb2bceb9851a8fb0b7f131343ee33dbd5 (patch)
tree32d1ac2794f73c599b9ff629ec6068fd9448ccc0 /src/eval/mod.rs
parent010ddc4795123987bdef3b5a60240203e7f11d01 (diff)
For loop patterns 🦚
Diffstat (limited to 'src/eval/mod.rs')
-rw-r--r--src/eval/mod.rs62
1 files changed, 44 insertions, 18 deletions
diff --git a/src/eval/mod.rs b/src/eval/mod.rs
index 27c66095..e04879d2 100644
--- a/src/eval/mod.rs
+++ b/src/eval/mod.rs
@@ -275,7 +275,7 @@ impl Eval for Spanned<&ExprBinary> {
impl Spanned<&ExprBinary> {
/// Apply a basic binary operation.
- fn apply<F>(&self, ctx: &mut EvalContext, op: F) -> Value
+ fn apply<F>(self, ctx: &mut EvalContext, op: F) -> Value
where
F: FnOnce(Value, Value) -> Value,
{
@@ -311,7 +311,7 @@ impl Spanned<&ExprBinary> {
}
/// Apply an assignment operation.
- fn assign<F>(&self, ctx: &mut EvalContext, op: F) -> Value
+ fn assign<F>(self, ctx: &mut EvalContext, op: F) -> Value
where
F: FnOnce(Value, Value) -> Value,
{
@@ -379,30 +379,56 @@ impl Eval for Spanned<&ExprFor> {
fn eval(self, ctx: &mut EvalContext) -> Self::Output {
let iter = self.v.iter.eval(ctx);
- if let Value::Array(array) = iter {
- let mut output = match self.v.body.v {
- Expr::Template(_) => Value::Template(vec![]),
- _ => Value::None,
- };
+ let mut output = if let Expr::Template(_) = self.v.body.v {
+ Value::Template(vec![])
+ } else {
+ Value::None
+ };
+
+ macro_rules! iterate {
+ (for ($($binding:ident => $value:ident),*) in $iter:expr) => {
+ #[allow(unused_parens)]
+ for ($($value),*) in $iter {
+ $(ctx.scopes.define($binding.as_str(), $value);)*
- for value in array {
- ctx.scopes.define(self.v.pat.v.as_str(), value);
- let value = self.v.body.eval(ctx);
+ let value = self.v.body.eval(ctx);
- if let Value::Template(prev) = &mut output {
- if let Value::Template(new) = value {
- prev.extend(new);
+ if let Value::Template(prev) = &mut output {
+ if let Value::Template(new) = value {
+ prev.extend(new);
+ }
}
}
+
+ return output;
+ };
+ }
+
+ match (self.v.pat.v.clone(), iter) {
+ (ForPattern::Value(v), Value::Str(string)) => {
+ iterate!(for (v => value) in string.chars().map(|c| Value::Str(c.into())));
+ }
+ (ForPattern::Value(v), Value::Array(array)) => {
+ iterate!(for (v => value) in array.into_iter());
+ }
+ (ForPattern::Value(v), Value::Dict(dict)) => {
+ iterate!(for (v => value) in dict.into_iter().map(|p| p.1));
+ }
+ (ForPattern::KeyValue(k, v), Value::Dict(dict)) => {
+ iterate!(for (k => key, v => value) in dict.into_iter());
}
- return output;
- } else if iter != Value::Error {
- ctx.diag(error!(
+ (ForPattern::KeyValue(..), Value::Str(_))
+ | (ForPattern::KeyValue(..), Value::Array(_)) => {
+ ctx.diag(error!(self.v.pat.span, "mismatched pattern",));
+ }
+
+ (_, Value::Error) => {}
+ (_, iter) => ctx.diag(error!(
self.v.iter.span,
- "expected array, found {}",
+ "cannot loop over {}",
iter.type_name(),
- ));
+ )),
}
Value::Error