boa/syntax/ast/node/block/
mod.rs

1//! Block AST node.
2
3use super::{Node, StatementList};
4use crate::{
5    environment::declarative_environment_record::DeclarativeEnvironmentRecord,
6    exec::Executable,
7    exec::InterpreterState,
8    gc::{Finalize, Trace},
9    BoaProfiler, Context, JsResult, JsValue,
10};
11use std::fmt;
12
13#[cfg(feature = "deser")]
14use serde::{Deserialize, Serialize};
15
16#[cfg(test)]
17mod tests;
18
19/// A `block` statement (or compound statement in other languages) is used to group zero or
20/// more statements.
21///
22/// The block statement is often called compound statement in other languages.
23/// It allows you to use multiple statements where JavaScript expects only one statement.
24/// Combining statements into blocks is a common practice in JavaScript. The opposite behavior
25/// is possible using an empty statement, where you provide no statement, although one is
26/// required.
27///
28/// More information:
29///  - [ECMAScript reference][spec]
30///  - [MDN documentation][mdn]
31///
32/// [spec]: https://tc39.es/ecma262/#prod-BlockStatement
33/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/block
34#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
35#[cfg_attr(feature = "deser", serde(transparent))]
36#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
37pub struct Block {
38    #[cfg_attr(feature = "deser", serde(flatten))]
39    statements: StatementList,
40}
41
42impl Block {
43    /// Gets the list of statements and declarations in this block.
44    pub(crate) fn items(&self) -> &[Node] {
45        self.statements.items()
46    }
47
48    /// Implements the display formatting with indentation.
49    pub(super) fn display(&self, f: &mut fmt::Formatter<'_>, indentation: usize) -> fmt::Result {
50        writeln!(f, "{{")?;
51        self.statements.display(f, indentation + 1)?;
52        write!(f, "{}}}", "    ".repeat(indentation))
53    }
54}
55
56impl Executable for Block {
57    fn run(&self, context: &mut Context) -> JsResult<JsValue> {
58        let _timer = BoaProfiler::global().start_event("Block", "exec");
59        {
60            let env = context.get_current_environment();
61            context.push_environment(DeclarativeEnvironmentRecord::new(Some(env)));
62        }
63
64        // https://tc39.es/ecma262/#sec-block-runtime-semantics-evaluation
65        // The return value is uninitialized, which means it defaults to Value::Undefined
66        let mut obj = JsValue::default();
67        for statement in self.items() {
68            obj = statement.run(context).map_err(|e| {
69                // No matter how control leaves the Block the LexicalEnvironment is always
70                // restored to its former state.
71                context.pop_environment();
72                e
73            })?;
74
75            match context.executor().get_current_state() {
76                InterpreterState::Return => {
77                    // Early return.
78                    break;
79                }
80                InterpreterState::Break(_label) => {
81                    // TODO, break to a label.
82
83                    // Early break.
84                    break;
85                }
86                InterpreterState::Continue(_label) => {
87                    // TODO, continue to a label
88                    break;
89                }
90                InterpreterState::Executing => {
91                    // Continue execution
92                }
93            }
94        }
95
96        // pop the block env
97        let _ = context.pop_environment();
98
99        Ok(obj)
100    }
101}
102
103impl<T> From<T> for Block
104where
105    T: Into<StatementList>,
106{
107    fn from(list: T) -> Self {
108        Self {
109            statements: list.into(),
110        }
111    }
112}
113
114impl fmt::Display for Block {
115    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116        self.display(f, 0)
117    }
118}
119
120impl From<Block> for Node {
121    fn from(block: Block) -> Self {
122        Self::Block(block)
123    }
124}