Skip to main content

boa_ast/
statement_list.rs

1//! Statement list node.
2
3use super::Declaration;
4use crate::{
5    LinearPosition,
6    statement::Statement,
7    visitor::{VisitWith, Visitor, VisitorMut},
8};
9use boa_interner::{Interner, ToIndentedString};
10use core::ops::ControlFlow;
11use std::ops::Deref;
12
13/// An item inside a [`StatementList`] Parse Node, as defined by the [spec].
14///
15/// Items in a `StatementList` can be either [`Declaration`]s (functions, classes, let/const declarations)
16/// or [`Statement`]s (if, while, var statement).
17///
18/// [spec]: https://tc39.es/ecma262/#prod-StatementListItem
19#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
21#[derive(Clone, Debug, PartialEq)]
22pub enum StatementListItem {
23    /// See [`Statement`].
24    Statement(Box<Statement>),
25    /// See [`Declaration`].
26    Declaration(Box<Declaration>),
27}
28
29impl ToIndentedString for StatementListItem {
30    /// Creates a string of the value of the node with the given indentation. For example, an
31    /// indent level of 2 would produce this:
32    ///
33    /// ```js
34    ///         function hello() {
35    ///             console.log("hello");
36    ///         }
37    ///         hello();
38    ///         a = 2;
39    /// ```
40    fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
41        let mut buf = "    ".repeat(indentation);
42
43        match self {
44            Self::Statement(stmt) => {
45                buf.push_str(&stmt.to_no_indent_string(interner, indentation));
46            }
47            Self::Declaration(decl) => {
48                buf.push_str(&decl.to_indented_string(interner, indentation));
49            }
50        }
51
52        buf
53    }
54}
55
56impl From<Statement> for StatementListItem {
57    #[inline]
58    fn from(stmt: Statement) -> Self {
59        Self::Statement(Box::new(stmt))
60    }
61}
62
63impl From<Declaration> for StatementListItem {
64    #[inline]
65    fn from(decl: Declaration) -> Self {
66        Self::Declaration(Box::new(decl))
67    }
68}
69
70impl VisitWith for StatementListItem {
71    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
72    where
73        V: Visitor<'a>,
74    {
75        match self {
76            Self::Statement(statement) => visitor.visit_statement(statement),
77            Self::Declaration(declaration) => visitor.visit_declaration(declaration),
78        }
79    }
80
81    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
82    where
83        V: VisitorMut<'a>,
84    {
85        match self {
86            Self::Statement(statement) => visitor.visit_statement_mut(statement),
87            Self::Declaration(declaration) => visitor.visit_declaration_mut(declaration),
88        }
89    }
90}
91
92/// List of statements.
93///
94/// More information:
95///  - [ECMAScript reference][spec]
96///
97/// [spec]: https://tc39.es/ecma262/#prod-StatementList
98#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
99#[derive(Clone, Debug, Default)]
100pub struct StatementList {
101    pub(crate) statements: Box<[StatementListItem]>,
102    linear_pos_end: LinearPosition,
103    strict: bool,
104}
105
106impl PartialEq for StatementList {
107    fn eq(&self, other: &Self) -> bool {
108        self.statements == other.statements && self.strict == other.strict
109    }
110}
111
112impl StatementList {
113    /// Creates a new `StatementList` AST node.
114    #[must_use]
115    pub fn new<S>(statements: S, linear_pos_end: LinearPosition, strict: bool) -> Self
116    where
117        S: Into<Box<[StatementListItem]>>,
118    {
119        Self {
120            statements: statements.into(),
121            linear_pos_end,
122            strict,
123        }
124    }
125
126    /// Gets the list of statements.
127    #[inline]
128    #[must_use]
129    pub const fn statements(&self) -> &[StatementListItem] {
130        &self.statements
131    }
132
133    /// Get the strict mode.
134    #[inline]
135    #[must_use]
136    pub const fn strict(&self) -> bool {
137        self.strict
138    }
139
140    /// Get end of linear position in source code.
141    #[inline]
142    #[must_use]
143    pub const fn linear_pos_end(&self) -> LinearPosition {
144        self.linear_pos_end
145    }
146}
147
148impl From<(Box<[StatementListItem]>, LinearPosition)> for StatementList {
149    #[inline]
150    fn from(value: (Box<[StatementListItem]>, LinearPosition)) -> Self {
151        Self {
152            statements: value.0,
153            linear_pos_end: value.1,
154            strict: false,
155        }
156    }
157}
158
159impl From<(Vec<StatementListItem>, LinearPosition)> for StatementList {
160    #[inline]
161    fn from(value: (Vec<StatementListItem>, LinearPosition)) -> Self {
162        Self {
163            statements: value.0.into(),
164            linear_pos_end: value.1,
165            strict: false,
166        }
167    }
168}
169
170impl Deref for StatementList {
171    type Target = [StatementListItem];
172
173    fn deref(&self) -> &Self::Target {
174        &self.statements
175    }
176}
177
178impl ToIndentedString for StatementList {
179    fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
180        let mut buf = String::new();
181        // Print statements
182        for item in &*self.statements {
183            // We rely on the node to add the correct indent.
184            buf.push_str(&item.to_indented_string(interner, indentation));
185
186            buf.push('\n');
187        }
188        buf
189    }
190}
191
192impl VisitWith for StatementList {
193    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
194    where
195        V: Visitor<'a>,
196    {
197        for statement in &*self.statements {
198            visitor.visit_statement_list_item(statement)?;
199        }
200        ControlFlow::Continue(())
201    }
202
203    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
204    where
205        V: VisitorMut<'a>,
206    {
207        for statement in &mut *self.statements {
208            visitor.visit_statement_list_item_mut(statement)?;
209        }
210        ControlFlow::Continue(())
211    }
212}
213
214#[cfg(feature = "arbitrary")]
215impl<'a> arbitrary::Arbitrary<'a> for StatementList {
216    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
217        Ok(Self {
218            statements: u.arbitrary()?,
219            linear_pos_end: LinearPosition::default(),
220            strict: false, // disable strictness; this is *not* in source data
221        })
222    }
223}