Early quit loop when body returns error 🛑

This commit is contained in:
Laurenz 2021-02-12 23:06:04 +01:00
parent 790dc9e667
commit 58f799c41c
2 changed files with 27 additions and 18 deletions

View File

@ -429,57 +429,59 @@ impl Eval for ExprFor {
fn eval(&self, ctx: &mut EvalContext) -> Self::Output { fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
macro_rules! iter { macro_rules! iter {
(for ($($binding:ident => $value:ident),*) in $iter:expr) => {{ (for ($($binding:ident => $value:ident),*) in $iter:expr) => {
let mut output = vec![]; let mut output = vec![];
ctx.scopes.push();
#[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);)*
if let Value::Template(new) = self.body.eval(ctx) { match self.body.eval(ctx) {
output.extend(new); Value::Template(new) => output.extend(new),
Value::Error => {
ctx.scopes.pop();
return Value::Error;
}
_ => {}
} }
} }
Value::Template(output) ctx.scopes.pop();
}}; return Value::Template(output);
};
} }
ctx.scopes.push();
let iter = self.iter.eval(ctx); let iter = self.iter.eval(ctx);
let value = match (self.pattern.clone(), iter) { match (self.pattern.clone(), iter) {
(ForPattern::Value(v), Value::Str(string)) => { (ForPattern::Value(v), Value::Str(string)) => {
iter!(for (v => value) in string.chars().map(|c| Value::Str(c.into()))) iter!(for (v => value) in string.chars().map(|c| Value::Str(c.into())));
} }
(ForPattern::Value(v), Value::Array(array)) => { (ForPattern::Value(v), Value::Array(array)) => {
iter!(for (v => value) in array.into_iter()) iter!(for (v => value) in array.into_iter());
} }
(ForPattern::Value(v), Value::Dict(dict)) => { (ForPattern::Value(v), Value::Dict(dict)) => {
iter!(for (v => value) in dict.into_iter().map(|p| p.1)) iter!(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)) => {
iter!(for (k => key, v => value) in dict.into_iter()) iter!(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.pattern.span(), "mismatched pattern")); ctx.diag(error!(self.pattern.span(), "mismatched pattern"));
Value::Error
} }
(_, Value::Error) => Value::Error, (_, Value::Error) => {}
(_, iter) => { (_, iter) => {
ctx.diag(error!( ctx.diag(error!(
self.iter.span(), self.iter.span(),
"cannot loop over {}", "cannot loop over {}",
iter.type_name(), iter.type_name(),
)); ));
}
}
Value::Error Value::Error
} }
};
ctx.scopes.pop();
value
}
} }

View File

@ -42,3 +42,10 @@
// Make sure that we don't complain twice. // Make sure that we don't complain twice.
// Error: 12-19 cannot add integer and string // Error: 12-19 cannot add integer and string
#for v #in 1 + "2" {} #for v #in 1 + "2" {}
// Error: 14-17 cannot apply '-' to string
#let error = -""
#let result = #for v #in (1, 2, 3) {
#if v < 2 [Ok] #else {error}
}
#[test result, error]