use super::{Context, Executable, InterpreterState};
use crate::{
environment::lexical_environment::new_declarative_environment,
syntax::ast::node::{DoWhileLoop, ForLoop, WhileLoop},
BoaProfiler, Result, Value,
};
#[cfg(test)]
mod tests;
macro_rules! handle_state_with_labels {
($self:ident, $label:ident, $interpreter:ident, $state:tt) => {{
if let Some(brk_label) = $label {
if let Some(stmt_label) = $self.label() {
if stmt_label != brk_label.as_ref() {
break;
}
} else {
break;
}
}
$interpreter
.executor()
.set_current_state(InterpreterState::Executing);
}};
}
impl Executable for ForLoop {
fn run(&self, interpreter: &mut Context) -> Result<Value> {
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.to_boolean()))
.transpose()?
.unwrap_or(true)
{
let result = self.body().run(interpreter)?;
match interpreter.executor().get_current_state() {
InterpreterState::Break(label) => {
handle_state_with_labels!(self, label, interpreter, break);
break;
}
InterpreterState::Continue(label) => {
handle_state_with_labels!(self, label, interpreter, continue);
}
InterpreterState::Return => {
return Ok(result);
}
InterpreterState::Executing => {
}
}
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 Context) -> Result<Value> {
let mut result = Value::undefined();
while self.cond().run(interpreter)?.to_boolean() {
result = self.expr().run(interpreter)?;
match interpreter.executor().get_current_state() {
InterpreterState::Break(label) => {
handle_state_with_labels!(self, label, interpreter, break);
break;
}
InterpreterState::Continue(label) => {
handle_state_with_labels!(self, label, interpreter, continue)
}
InterpreterState::Return => {
return Ok(result);
}
InterpreterState::Executing => {
}
}
}
Ok(result)
}
}
impl Executable for DoWhileLoop {
fn run(&self, interpreter: &mut Context) -> Result<Value> {
let mut result = self.body().run(interpreter)?;
match interpreter.executor().get_current_state() {
InterpreterState::Break(_label) => {
interpreter
.executor()
.set_current_state(InterpreterState::Executing);
return Ok(result);
}
InterpreterState::Continue(_label) => {
interpreter
.executor()
.set_current_state(InterpreterState::Executing);
}
InterpreterState::Return => {
return Ok(result);
}
InterpreterState::Executing => {
}
}
while self.cond().run(interpreter)?.to_boolean() {
result = self.body().run(interpreter)?;
match interpreter.executor().get_current_state() {
InterpreterState::Break(_label) => {
interpreter
.executor()
.set_current_state(InterpreterState::Executing);
break;
}
InterpreterState::Continue(_label) => {
interpreter
.executor()
.set_current_state(InterpreterState::Executing);
}
InterpreterState::Return => {
return Ok(result);
}
InterpreterState::Executing => {
}
}
}
Ok(result)
}
}