use super::Node;
use gc::{Finalize, Trace};
use std::fmt;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
pub struct ForLoop {
#[cfg_attr(feature = "serde", serde(flatten))]
inner: Box<InnerForLoop>,
label: Option<Box<str>>,
}
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(super) fn display(&self, f: &mut fmt::Formatter<'_>, indentation: usize) -> fmt::Result {
f.write_str("for (")?;
if let Some(init) = self.init() {
fmt::Display::fmt(init, f)?;
}
f.write_str(";")?;
if let Some(condition) = self.condition() {
fmt::Display::fmt(condition, f)?;
}
f.write_str(";")?;
if let Some(final_expr) = self.final_expr() {
fmt::Display::fmt(final_expr, f)?;
}
writeln!(f, ") {{")?;
self.inner.body().display(f, indentation + 1)?;
write!(f, "}}")
}
pub fn label(&self) -> Option<&str> {
self.label.as_ref().map(Box::as_ref)
}
pub fn set_label(&mut self, label: Box<str>) {
self.label = Some(label);
}
}
impl fmt::Display for ForLoop {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.display(f, 0)
}
}
impl From<ForLoop> for Node {
fn from(for_loop: ForLoop) -> Self {
Self::ForLoop(for_loop)
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, Trace, Finalize, 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
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
pub struct WhileLoop {
cond: Box<Node>,
expr: Box<Node>,
label: Option<Box<str>>,
}
impl WhileLoop {
pub fn cond(&self) -> &Node {
&self.cond
}
pub fn expr(&self) -> &Node {
&self.expr
}
pub fn label(&self) -> Option<&str> {
self.label.as_ref().map(Box::as_ref)
}
pub fn new<C, B>(condition: C, body: B) -> Self
where
C: Into<Node>,
B: Into<Node>,
{
Self {
cond: Box::new(condition.into()),
expr: Box::new(body.into()),
label: None,
}
}
pub(super) fn display(&self, f: &mut fmt::Formatter<'_>, indentation: usize) -> fmt::Result {
write!(f, "while ({}) ", self.cond())?;
self.expr().display(f, indentation)
}
}
impl fmt::Display for WhileLoop {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.display(f, 0)
}
}
impl From<WhileLoop> for Node {
fn from(while_loop: WhileLoop) -> Self {
Self::WhileLoop(while_loop)
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
pub struct DoWhileLoop {
body: Box<Node>,
cond: Box<Node>,
label: Option<Box<str>>,
}
impl DoWhileLoop {
pub fn body(&self) -> &Node {
&self.body
}
pub fn cond(&self) -> &Node {
&self.cond
}
pub fn label(&self) -> Option<&str> {
self.label.as_ref().map(Box::as_ref)
}
pub fn new<B, C>(body: B, condition: C) -> Self
where
B: Into<Node>,
C: Into<Node>,
{
Self {
body: Box::new(body.into()),
cond: Box::new(condition.into()),
label: None,
}
}
pub(super) fn display(&self, f: &mut fmt::Formatter<'_>, indentation: usize) -> fmt::Result {
write!(f, "do")?;
self.body().display(f, indentation)?;
write!(f, "while ({})", self.cond())
}
}
impl fmt::Display for DoWhileLoop {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.display(f, 0)
}
}
impl From<DoWhileLoop> for Node {
fn from(do_while: DoWhileLoop) -> Self {
Self::DoWhileLoop(do_while)
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
pub struct Continue {
label: Option<Box<str>>,
}
impl Continue {
pub fn label(&self) -> Option<&str> {
self.label.as_ref().map(Box::as_ref)
}
pub fn new<OL, L>(label: OL) -> Self
where
L: Into<Box<str>>,
OL: Into<Option<L>>,
{
Self {
label: label.into().map(L::into),
}
}
}
impl fmt::Display for Continue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"continue{}",
if let Some(label) = self.label() {
format!(" {}", label)
} else {
String::new()
}
)
}
}
impl From<Continue> for Node {
fn from(cont: Continue) -> Node {
Self::Continue(cont)
}
}