use crate::{
expression::Expression,
statement::Statement,
visitor::{VisitWith, Visitor, VisitorMut},
};
use boa_interner::{Interner, ToIndentedString, ToInternedString};
use core::{fmt::Write as _, ops::ControlFlow};
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)]
pub struct If {
condition: Expression,
body: Box<Statement>,
else_node: Option<Box<Statement>>,
}
impl If {
#[inline]
#[must_use]
pub const fn cond(&self) -> &Expression {
&self.condition
}
#[inline]
#[must_use]
pub const fn body(&self) -> &Statement {
&self.body
}
#[inline]
pub fn else_node(&self) -> Option<&Statement> {
self.else_node.as_ref().map(Box::as_ref)
}
#[inline]
#[must_use]
pub fn new(condition: Expression, body: Statement, else_node: Option<Statement>) -> Self {
Self {
condition,
body: body.into(),
else_node: else_node.map(Box::new),
}
}
}
impl ToIndentedString for If {
fn to_indented_string(&self, interner: &Interner, indent: usize) -> String {
let mut buf = format!("if ({}) ", self.cond().to_interned_string(interner));
match self.else_node() {
Some(else_e) => {
let _ = write!(
buf,
"{} else {}",
self.body().to_indented_string(interner, indent),
else_e.to_indented_string(interner, indent)
);
}
None => {
buf.push_str(&self.body().to_indented_string(interner, indent));
}
}
buf
}
}
impl From<If> for Statement {
fn from(if_stm: If) -> Self {
Self::If(if_stm)
}
}
impl VisitWith for If {
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
where
V: Visitor<'a>,
{
visitor.visit_expression(&self.condition)?;
visitor.visit_statement(&self.body)?;
if let Some(stmt) = &self.else_node {
visitor.visit_statement(stmt)?;
}
ControlFlow::Continue(())
}
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
where
V: VisitorMut<'a>,
{
visitor.visit_expression_mut(&mut self.condition)?;
visitor.visit_statement_mut(&mut self.body)?;
if let Some(stmt) = &mut self.else_node {
visitor.visit_statement_mut(stmt)?;
}
ControlFlow::Continue(())
}
}