use super::Declaration;
use crate::{
LinearPosition,
statement::Statement,
visitor::{VisitWith, Visitor, VisitorMut},
};
use boa_interner::{Interner, ToIndentedString};
use core::ops::ControlFlow;
use std::ops::Deref;
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)]
pub enum StatementListItem {
Statement(Box<Statement>),
Declaration(Box<Declaration>),
}
impl ToIndentedString for StatementListItem {
fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
let mut buf = " ".repeat(indentation);
match self {
Self::Statement(stmt) => {
buf.push_str(&stmt.to_no_indent_string(interner, indentation));
}
Self::Declaration(decl) => {
buf.push_str(&decl.to_indented_string(interner, indentation));
}
}
buf
}
}
impl From<Statement> for StatementListItem {
#[inline]
fn from(stmt: Statement) -> Self {
Self::Statement(Box::new(stmt))
}
}
impl From<Declaration> for StatementListItem {
#[inline]
fn from(decl: Declaration) -> Self {
Self::Declaration(Box::new(decl))
}
}
impl VisitWith for StatementListItem {
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
where
V: Visitor<'a>,
{
match self {
Self::Statement(statement) => visitor.visit_statement(statement),
Self::Declaration(declaration) => visitor.visit_declaration(declaration),
}
}
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
where
V: VisitorMut<'a>,
{
match self {
Self::Statement(statement) => visitor.visit_statement_mut(statement),
Self::Declaration(declaration) => visitor.visit_declaration_mut(declaration),
}
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Debug, Default)]
pub struct StatementList {
pub(crate) statements: Box<[StatementListItem]>,
linear_pos_end: LinearPosition,
strict: bool,
}
impl PartialEq for StatementList {
fn eq(&self, other: &Self) -> bool {
self.statements == other.statements && self.strict == other.strict
}
}
impl StatementList {
#[must_use]
pub fn new<S>(statements: S, linear_pos_end: LinearPosition, strict: bool) -> Self
where
S: Into<Box<[StatementListItem]>>,
{
Self {
statements: statements.into(),
linear_pos_end,
strict,
}
}
#[inline]
#[must_use]
pub const fn statements(&self) -> &[StatementListItem] {
&self.statements
}
#[inline]
#[must_use]
pub const fn strict(&self) -> bool {
self.strict
}
#[inline]
#[must_use]
pub const fn linear_pos_end(&self) -> LinearPosition {
self.linear_pos_end
}
}
impl From<(Box<[StatementListItem]>, LinearPosition)> for StatementList {
#[inline]
fn from(value: (Box<[StatementListItem]>, LinearPosition)) -> Self {
Self {
statements: value.0,
linear_pos_end: value.1,
strict: false,
}
}
}
impl From<(Vec<StatementListItem>, LinearPosition)> for StatementList {
#[inline]
fn from(value: (Vec<StatementListItem>, LinearPosition)) -> Self {
Self {
statements: value.0.into(),
linear_pos_end: value.1,
strict: false,
}
}
}
impl Deref for StatementList {
type Target = [StatementListItem];
fn deref(&self) -> &Self::Target {
&self.statements
}
}
impl ToIndentedString for StatementList {
fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
let mut buf = String::new();
for item in &*self.statements {
buf.push_str(&item.to_indented_string(interner, indentation));
buf.push('\n');
}
buf
}
}
impl VisitWith for StatementList {
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
where
V: Visitor<'a>,
{
for statement in &*self.statements {
visitor.visit_statement_list_item(statement)?;
}
ControlFlow::Continue(())
}
fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
where
V: VisitorMut<'a>,
{
for statement in &mut *self.statements {
visitor.visit_statement_list_item_mut(statement)?;
}
ControlFlow::Continue(())
}
}
#[cfg(feature = "arbitrary")]
impl<'a> arbitrary::Arbitrary<'a> for StatementList {
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
Ok(Self {
statements: u.arbitrary()?,
linear_pos_end: LinearPosition::default(),
strict: false, })
}
}