use crate::syntax::ast::node::Node;
use boa_interner::{Interner, Sym, ToInternedString};
#[cfg(feature = "deser")]
use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq)]
pub struct ForLoop {
#[cfg_attr(feature = "deser", serde(flatten))]
inner: Box<InnerForLoop>,
label: Option<Sym>,
}
impl ForLoop {
pub(in crate::syntax) fn new<I, C, E, B>(init: I, condition: C, final_expr: E, body: B) -> Self
where
I: Into<Option<Node>>,
C: Into<Option<Node>>,
E: Into<Option<Node>>,
B: Into<Node>,
{
Self {
inner: Box::new(InnerForLoop::new(init, condition, final_expr, body)),
label: None,
}
}
pub fn init(&self) -> Option<&Node> {
self.inner.init()
}
pub fn condition(&self) -> Option<&Node> {
self.inner.condition()
}
pub fn final_expr(&self) -> Option<&Node> {
self.inner.final_expr()
}
pub fn body(&self) -> &Node {
self.inner.body()
}
pub(in crate::syntax::ast::node) fn to_indented_string(
&self,
interner: &Interner,
indentation: usize,
) -> String {
let mut buf = if let Some(label) = self.label {
format!("{}: ", interner.resolve_expect(label))
} else {
String::new()
};
buf.push_str("for (");
if let Some(init) = self.init() {
buf.push_str(&init.to_interned_string(interner));
}
buf.push_str("; ");
if let Some(condition) = self.condition() {
buf.push_str(&condition.to_interned_string(interner));
}
buf.push_str("; ");
if let Some(final_expr) = self.final_expr() {
buf.push_str(&final_expr.to_interned_string(interner));
}
buf.push_str(&format!(
") {}",
self.inner.body().to_indented_string(interner, indentation)
));
buf
}
pub fn label(&self) -> Option<Sym> {
self.label
}
pub fn set_label(&mut self, label: Sym) {
self.label = Some(label);
}
}
impl ToInternedString for ForLoop {
fn to_interned_string(&self, interner: &Interner) -> String {
self.to_indented_string(interner, 0)
}
}
impl From<ForLoop> for Node {
fn from(for_loop: ForLoop) -> Self {
Self::ForLoop(for_loop)
}
}
#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq)]
struct InnerForLoop {
init: Option<Node>,
condition: Option<Node>,
final_expr: Option<Node>,
body: Node,
}
impl InnerForLoop {
fn new<I, C, E, B>(init: I, condition: C, final_expr: E, body: B) -> Self
where
I: Into<Option<Node>>,
C: Into<Option<Node>>,
E: Into<Option<Node>>,
B: Into<Node>,
{
Self {
init: init.into(),
condition: condition.into(),
final_expr: final_expr.into(),
body: body.into(),
}
}
fn init(&self) -> Option<&Node> {
self.init.as_ref()
}
fn condition(&self) -> Option<&Node> {
self.condition.as_ref()
}
fn final_expr(&self) -> Option<&Node> {
self.final_expr.as_ref()
}
fn body(&self) -> &Node {
&self.body
}
}