Skip to main content

boa_ast/statement/
block.rs

1//! Block AST node.
2
3use crate::{
4    Statement, StatementList,
5    operations::{ContainsSymbol, contains},
6    scope::Scope,
7    visitor::{VisitWith, Visitor, VisitorMut},
8};
9use boa_interner::{Interner, ToIndentedString};
10use core::ops::ControlFlow;
11
12/// A `block` statement (or compound statement in other languages) is used to group zero or
13/// more statements.
14///
15/// The block statement is often called compound statement in other languages.
16/// It allows you to use multiple statements where ECMAScript expects only one statement.
17/// Combining statements into blocks is a common practice in ECMAScript. The opposite behavior
18/// is possible using an empty statement, where you provide no statement, although one is
19/// required.
20///
21/// More information:
22///  - [ECMAScript reference][spec]
23///  - [MDN documentation][mdn]
24///
25/// [spec]: https://tc39.es/ecma262/#prod-BlockStatement
26/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/block
27#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
28#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
29#[derive(Clone, Debug, PartialEq, Default)]
30pub struct Block {
31    #[cfg_attr(feature = "serde", serde(flatten))]
32    pub(crate) statements: StatementList,
33    pub(crate) contains_direct_eval: bool,
34
35    #[cfg_attr(feature = "serde", serde(skip))]
36    pub(crate) scope: Option<Scope>,
37}
38
39impl Block {
40    /// Gets the list of statements and declarations in this block.
41    #[inline]
42    #[must_use]
43    pub const fn statement_list(&self) -> &StatementList {
44        &self.statements
45    }
46
47    /// Gets the scope of the block.
48    #[inline]
49    #[must_use]
50    pub const fn scope(&self) -> Option<&Scope> {
51        self.scope.as_ref()
52    }
53}
54
55impl<T> From<T> for Block
56where
57    T: Into<StatementList>,
58{
59    fn from(list: T) -> Self {
60        let statements = list.into();
61        let contains_direct_eval = contains(&statements, ContainsSymbol::DirectEval);
62        Self {
63            statements,
64            scope: None,
65            contains_direct_eval,
66        }
67    }
68}
69
70impl ToIndentedString for Block {
71    fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
72        format!(
73            "{{\n{}{}}}",
74            self.statements
75                .to_indented_string(interner, indentation + 1),
76            "    ".repeat(indentation)
77        )
78    }
79}
80
81impl From<Block> for Statement {
82    #[inline]
83    fn from(block: Block) -> Self {
84        Self::Block(block)
85    }
86}
87
88impl VisitWith for Block {
89    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
90    where
91        V: Visitor<'a>,
92    {
93        visitor.visit_statement_list(&self.statements)
94    }
95
96    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
97    where
98        V: VisitorMut<'a>,
99    {
100        visitor.visit_statement_list_mut(&mut self.statements)
101    }
102}