Skip evaluate condition for loop statement.
This commit is contained in:
parent
e14bef4b10
commit
a126d05c3f
@ -823,7 +823,7 @@ pub enum Stmt {
|
|||||||
Position,
|
Position,
|
||||||
),
|
),
|
||||||
/// `while` expr `{` stmt `}`
|
/// `while` expr `{` stmt `}`
|
||||||
While(Expr, Box<Stmt>, Position),
|
While(Option<Expr>, Box<Stmt>, Position),
|
||||||
/// `do` `{` stmt `}` `while`|`until` expr
|
/// `do` `{` stmt `}` `while`|`until` expr
|
||||||
Do(Box<Stmt>, Expr, bool, Position),
|
Do(Box<Stmt>, Expr, bool, Position),
|
||||||
/// `for` id `in` expr `{` stmt `}`
|
/// `for` id `in` expr `{` stmt `}`
|
||||||
@ -981,9 +981,10 @@ impl Stmt {
|
|||||||
&& x.0.values().all(Stmt::is_pure)
|
&& x.0.values().all(Stmt::is_pure)
|
||||||
&& x.1.as_ref().map(Stmt::is_pure).unwrap_or(true)
|
&& x.1.as_ref().map(Stmt::is_pure).unwrap_or(true)
|
||||||
}
|
}
|
||||||
Self::While(condition, block, _) | Self::Do(block, condition, _, _) => {
|
Self::While(Some(condition), block, _) | Self::Do(block, condition, _, _) => {
|
||||||
condition.is_pure() && block.is_pure()
|
condition.is_pure() && block.is_pure()
|
||||||
}
|
}
|
||||||
|
Self::While(None, block, _) => block.is_pure(),
|
||||||
Self::For(iterable, x, _) => iterable.is_pure() && x.1.is_pure(),
|
Self::For(iterable, x, _) => iterable.is_pure() && x.1.is_pure(),
|
||||||
Self::Let(_, _, _, _) | Self::Const(_, _, _, _) | Self::Assignment(_, _) => false,
|
Self::Let(_, _, _, _) | Self::Const(_, _, _, _) | Self::Assignment(_, _) => false,
|
||||||
Self::Block(block, _) => block.iter().all(|stmt| stmt.is_pure()),
|
Self::Block(block, _) => block.iter().all(|stmt| stmt.is_pure()),
|
||||||
@ -1021,10 +1022,11 @@ impl Stmt {
|
|||||||
s.walk(path, on_node);
|
s.walk(path, on_node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::While(e, s, _) | Self::Do(s, e, _, _) => {
|
Self::While(Some(e), s, _) | Self::Do(s, e, _, _) => {
|
||||||
e.walk(path, on_node);
|
e.walk(path, on_node);
|
||||||
s.walk(path, on_node);
|
s.walk(path, on_node);
|
||||||
}
|
}
|
||||||
|
Self::While(None, s, _) => s.walk(path, on_node),
|
||||||
Self::For(e, x, _) => {
|
Self::For(e, x, _) => {
|
||||||
e.walk(path, on_node);
|
e.walk(path, on_node);
|
||||||
x.1.walk(path, on_node);
|
x.1.walk(path, on_node);
|
||||||
|
@ -2138,24 +2138,25 @@ impl Engine {
|
|||||||
|
|
||||||
// While loop
|
// While loop
|
||||||
Stmt::While(expr, body, _) => loop {
|
Stmt::While(expr, body, _) => loop {
|
||||||
match self
|
let condition = if let Some(expr) = expr {
|
||||||
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
|
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
|
||||||
.as_bool()
|
.as_bool()
|
||||||
{
|
.map_err(|err| self.make_type_mismatch_err::<bool>(err, expr.position()))?
|
||||||
Ok(true) => {
|
} else {
|
||||||
match self.eval_stmt(scope, mods, state, lib, this_ptr, body, level) {
|
true
|
||||||
Ok(_) => (),
|
};
|
||||||
Err(err) => match *err {
|
|
||||||
EvalAltResult::LoopBreak(false, _) => (),
|
if condition {
|
||||||
EvalAltResult::LoopBreak(true, _) => return Ok(Dynamic::UNIT),
|
match self.eval_stmt(scope, mods, state, lib, this_ptr, body, level) {
|
||||||
_ => return Err(err),
|
Ok(_) => (),
|
||||||
},
|
Err(err) => match *err {
|
||||||
}
|
EvalAltResult::LoopBreak(false, _) => (),
|
||||||
}
|
EvalAltResult::LoopBreak(true, _) => return Ok(Dynamic::UNIT),
|
||||||
Ok(false) => return Ok(Dynamic::UNIT),
|
_ => return Err(err),
|
||||||
Err(err) => {
|
},
|
||||||
return Err(self.make_type_mismatch_err::<bool>(err, expr.position()))
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return Ok(Dynamic::UNIT);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -2170,15 +2171,17 @@ impl Engine {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
match self
|
if self
|
||||||
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
|
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
|
||||||
.as_bool()
|
.as_bool()
|
||||||
|
.map_err(|err| self.make_type_mismatch_err::<bool>(err, expr.position()))?
|
||||||
{
|
{
|
||||||
Ok(true) if !*is_while => return Ok(Dynamic::UNIT),
|
if !*is_while {
|
||||||
Ok(false) if *is_while => return Ok(Dynamic::UNIT),
|
return Ok(Dynamic::UNIT);
|
||||||
Ok(_) => (),
|
}
|
||||||
Err(err) => {
|
} else {
|
||||||
return Err(self.make_type_mismatch_err::<bool>(err, expr.position()))
|
if *is_while {
|
||||||
|
return Ok(Dynamic::UNIT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -393,25 +393,32 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// while false { block } -> Noop
|
// while false { block } -> Noop
|
||||||
Stmt::While(Expr::BoolConstant(false, pos), _, _) => {
|
Stmt::While(Some(Expr::BoolConstant(false, pos)), _, _) => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*stmt = Stmt::Noop(*pos)
|
*stmt = Stmt::Noop(*pos)
|
||||||
}
|
}
|
||||||
// while expr { block }
|
// while expr { block }
|
||||||
Stmt::While(condition, block, _) => {
|
Stmt::While(condition, block, _) => {
|
||||||
optimize_stmt(block, state, false);
|
optimize_stmt(block, state, false);
|
||||||
optimize_expr(condition, state);
|
|
||||||
|
if let Some(condition) = condition {
|
||||||
|
optimize_expr(condition, state);
|
||||||
|
}
|
||||||
|
|
||||||
match **block {
|
match **block {
|
||||||
// while expr { break; } -> { expr; }
|
// while expr { break; } -> { expr; }
|
||||||
Stmt::Break(pos) => {
|
Stmt::Break(pos) => {
|
||||||
// Only a single break statement - turn into running the guard expression once
|
// Only a single break statement - turn into running the guard expression once
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
let mut statements = vec![Stmt::Expr(mem::take(condition))];
|
if let Some(condition) = condition {
|
||||||
if preserve_result {
|
let mut statements = vec![Stmt::Expr(mem::take(condition))];
|
||||||
statements.push(Stmt::Noop(pos))
|
if preserve_result {
|
||||||
}
|
statements.push(Stmt::Noop(pos))
|
||||||
*stmt = Stmt::Block(statements, pos);
|
}
|
||||||
|
*stmt = Stmt::Block(statements, pos);
|
||||||
|
} else {
|
||||||
|
*stmt = Stmt::Noop(pos);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
@ -2122,9 +2122,10 @@ fn parse_while_loop(
|
|||||||
let (guard, token_pos) = match input.next().unwrap() {
|
let (guard, token_pos) = match input.next().unwrap() {
|
||||||
(Token::While, pos) => {
|
(Token::While, pos) => {
|
||||||
ensure_not_statement_expr(input, "a boolean")?;
|
ensure_not_statement_expr(input, "a boolean")?;
|
||||||
(parse_expr(input, state, lib, settings.level_up())?, pos)
|
let expr = parse_expr(input, state, lib, settings.level_up())?;
|
||||||
|
(Some(expr), pos)
|
||||||
}
|
}
|
||||||
(Token::Loop, pos) => (Expr::BoolConstant(true, pos), pos),
|
(Token::Loop, pos) => (None, pos),
|
||||||
(t, _) => unreachable!("expecting Token::While or Token::Loop, but gets {:?}", t),
|
(t, _) => unreachable!("expecting Token::While or Token::Loop, but gets {:?}", t),
|
||||||
};
|
};
|
||||||
settings.pos = token_pos;
|
settings.pos = token_pos;
|
||||||
|
Loading…
Reference in New Issue
Block a user