1use crate::{
4 expression::Expression,
5 statement::Statement,
6 visitor::{VisitWith, Visitor, VisitorMut},
7};
8use boa_interner::{Interner, ToIndentedString, ToInternedString};
9use core::{fmt::Write as _, ops::ControlFlow};
10
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
28#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
29#[derive(Clone, Debug, PartialEq)]
30pub struct If {
31 condition: Expression,
32 body: Box<Statement>,
33 else_node: Option<Box<Statement>>,
34}
35
36impl If {
37 #[inline]
39 #[must_use]
40 pub const fn cond(&self) -> &Expression {
41 &self.condition
42 }
43
44 #[inline]
46 #[must_use]
47 pub const fn body(&self) -> &Statement {
48 &self.body
49 }
50
51 #[inline]
53 pub fn else_node(&self) -> Option<&Statement> {
54 self.else_node.as_ref().map(Box::as_ref)
55 }
56
57 #[inline]
59 #[must_use]
60 pub fn new(condition: Expression, body: Statement, else_node: Option<Statement>) -> Self {
61 Self {
62 condition,
63 body: body.into(),
64 else_node: else_node.map(Box::new),
65 }
66 }
67}
68
69impl ToIndentedString for If {
70 fn to_indented_string(&self, interner: &Interner, indent: usize) -> String {
71 let mut buf = format!("if ({}) ", self.cond().to_interned_string(interner));
72 match self.else_node() {
73 Some(else_e) => {
74 let _ = write!(
75 buf,
76 "{} else {}",
77 self.body().to_indented_string(interner, indent),
78 else_e.to_indented_string(interner, indent)
79 );
80 }
81 None => {
82 buf.push_str(&self.body().to_indented_string(interner, indent));
83 }
84 }
85 buf
86 }
87}
88
89impl From<If> for Statement {
90 fn from(if_stm: If) -> Self {
91 Self::If(if_stm)
92 }
93}
94
95impl VisitWith for If {
96 fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
97 where
98 V: Visitor<'a>,
99 {
100 visitor.visit_expression(&self.condition)?;
101 visitor.visit_statement(&self.body)?;
102 if let Some(stmt) = &self.else_node {
103 visitor.visit_statement(stmt)?;
104 }
105 ControlFlow::Continue(())
106 }
107
108 fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
109 where
110 V: VisitorMut<'a>,
111 {
112 visitor.visit_expression_mut(&mut self.condition)?;
113 visitor.visit_statement_mut(&mut self.body)?;
114 if let Some(stmt) = &mut self.else_node {
115 visitor.visit_statement_mut(stmt)?;
116 }
117 ControlFlow::Continue(())
118 }
119}