Scoped for loop bindings 🏔️

Previously for loop bindings were leaked until after the loop.
This commit is contained in:
Laurenz 2021-01-30 16:26:21 +01:00
parent 5943f552e5
commit bcb2c46a10

View File

@ -410,11 +410,10 @@ impl Eval for Spanned<&ExprFor> {
type Output = Value; type Output = Value;
fn eval(self, ctx: &mut EvalContext) -> Self::Output { fn eval(self, ctx: &mut EvalContext) -> Self::Output {
let iter = self.v.iter.eval(ctx);
let mut output = vec![];
macro_rules! iterate { macro_rules! iterate {
(for ($($binding:ident => $value:ident),*) in $iter:expr) => { (for ($($binding:ident => $value:ident),*) in $iter:expr) => {{
let mut output = vec![];
#[allow(unused_parens)] #[allow(unused_parens)]
for ($($value),*) in $iter { for ($($value),*) in $iter {
$(ctx.scopes.def_mut($binding.as_str(), $value);)* $(ctx.scopes.def_mut($binding.as_str(), $value);)*
@ -424,37 +423,45 @@ impl Eval for Spanned<&ExprFor> {
} }
} }
return Value::Template(output); Value::Template(output)
}; }};
} }
match (self.v.pat.v.clone(), iter) { ctx.scopes.push();
let iter = self.v.iter.eval(ctx);
let value = match (self.v.pat.v.clone(), iter) {
(ForPattern::Value(v), Value::Str(string)) => { (ForPattern::Value(v), Value::Str(string)) => {
iterate!(for (v => value) in string.chars().map(|c| Value::Str(c.into()))); iterate!(for (v => value) in string.chars().map(|c| Value::Str(c.into())))
} }
(ForPattern::Value(v), Value::Array(array)) => { (ForPattern::Value(v), Value::Array(array)) => {
iterate!(for (v => value) in array.into_iter()); iterate!(for (v => value) in array.into_iter())
} }
(ForPattern::Value(v), Value::Dict(dict)) => { (ForPattern::Value(v), Value::Dict(dict)) => {
iterate!(for (v => value) in dict.into_iter().map(|p| p.1)); iterate!(for (v => value) in dict.into_iter().map(|p| p.1))
} }
(ForPattern::KeyValue(k, v), Value::Dict(dict)) => { (ForPattern::KeyValue(k, v), Value::Dict(dict)) => {
iterate!(for (k => key, v => value) in dict.into_iter()); iterate!(for (k => key, v => value) in dict.into_iter())
} }
(ForPattern::KeyValue(..), Value::Str(_)) (ForPattern::KeyValue(..), Value::Str(_))
| (ForPattern::KeyValue(..), Value::Array(_)) => { | (ForPattern::KeyValue(..), Value::Array(_)) => {
ctx.diag(error!(self.v.pat.span, "mismatched pattern")); ctx.diag(error!(self.v.pat.span, "mismatched pattern"));
Value::Error
} }
(_, Value::Error) => {} (_, Value::Error) => Value::Error,
(_, iter) => ctx.diag(error!( (_, iter) => {
self.v.iter.span, ctx.diag(error!(
"cannot loop over {}", self.v.iter.span,
iter.type_name(), "cannot loop over {}",
)), iter.type_name(),
} ));
Value::Error
}
};
Value::Error ctx.scopes.pop();
value
} }
} }