use super::{Executable, Interpreter, InterpreterState};
use crate::{
builtins::value::{ResultValue, Value},
environment::lexical_environment::new_declarative_environment,
syntax::ast::node::{DoWhileLoop, ForLoop, WhileLoop},
BoaProfiler,
};
use std::borrow::Borrow;
#[cfg(test)]
mod tests;
impl Executable for ForLoop {
fn run(&self, interpreter: &mut Interpreter) -> ResultValue {
let _timer = BoaProfiler::global().start_event("ForLoop", "exec");
{
let env = &mut interpreter.realm_mut().environment;
env.push(new_declarative_environment(Some(
env.get_current_environment_ref().clone(),
)));
}
if let Some(init) = self.init() {
init.run(interpreter)?;
}
while self
.condition()
.map(|cond| cond.run(interpreter).map(|v| v.is_true()))
.transpose()?
.unwrap_or(true)
{
let result = self.body().run(interpreter)?;
match interpreter.get_current_state() {
InterpreterState::Break(_label) => {
interpreter.set_current_state(InterpreterState::Executing);
break;
}
InterpreterState::Return => {
return Ok(result);
}
_ => {
}
}
if let Some(final_expr) = self.final_expr() {
final_expr.run(interpreter)?;
}
}
let _ = interpreter.realm_mut().environment.pop();
Ok(Value::undefined())
}
}
impl Executable for WhileLoop {
fn run(&self, interpreter: &mut Interpreter) -> ResultValue {
let mut result = Value::undefined();
while self.cond().run(interpreter)?.borrow().is_true() {
result = self.expr().run(interpreter)?;
match interpreter.get_current_state() {
InterpreterState::Break(_label) => {
interpreter.set_current_state(InterpreterState::Executing);
break;
}
InterpreterState::Return => {
return Ok(result);
}
_ => {
}
}
}
Ok(result)
}
}
impl Executable for DoWhileLoop {
fn run(&self, interpreter: &mut Interpreter) -> ResultValue {
let mut result = self.body().run(interpreter)?;
match interpreter.get_current_state() {
InterpreterState::Break(_label) => {
interpreter.set_current_state(InterpreterState::Executing);
return Ok(result);
}
InterpreterState::Return => {
return Ok(result);
}
_ => {
}
}
while self.cond().run(interpreter)?.borrow().is_true() {
result = self.body().run(interpreter)?;
match interpreter.get_current_state() {
InterpreterState::Break(_label) => {
interpreter.set_current_state(InterpreterState::Executing);
break;
}
InterpreterState::Return => {
return Ok(result);
}
_ => {
}
}
}
Ok(result)
}
}