boa/syntax/ast/node/statement_list/
mod.rs1use crate::{
4 context::StrictType,
5 exec::{Executable, InterpreterState},
6 gc::{empty_trace, Finalize, Trace},
7 syntax::ast::node::{Declaration, Node},
8 BoaProfiler, Context, JsResult, JsValue,
9};
10use std::{collections::HashSet, fmt, ops::Deref, rc::Rc};
11
12#[cfg(feature = "deser")]
13use serde::{Deserialize, Serialize};
14
15#[cfg(test)]
16mod tests;
17
18#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
27#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
28pub struct StatementList {
29 #[cfg_attr(feature = "deser", serde(flatten))]
30 items: Box<[Node]>,
31 strict: bool,
32}
33
34impl StatementList {
35 #[inline]
37 pub fn items(&self) -> &[Node] {
38 &self.items
39 }
40
41 #[inline]
43 pub fn strict(&self) -> bool {
44 self.strict
45 }
46
47 #[inline]
49 pub fn set_strict(&mut self, strict: bool) {
50 self.strict = strict;
51 }
52
53 pub(in crate::syntax::ast::node) fn display(
55 &self,
56 f: &mut fmt::Formatter<'_>,
57 indentation: usize,
58 ) -> fmt::Result {
59 for node in self.items.iter() {
61 node.display(f, indentation)?;
63
64 match node {
65 Node::Block(_) | Node::If(_) | Node::Switch(_) | Node::WhileLoop(_) => {}
66 _ => write!(f, ";")?,
67 }
68 writeln!(f)?;
69 }
70 Ok(())
71 }
72
73 pub fn lexically_declared_names(&self) -> HashSet<&str> {
74 let mut set = HashSet::new();
75 for stmt in self.items() {
76 if let Node::LetDeclList(decl_list) | Node::ConstDeclList(decl_list) = stmt {
77 for decl in decl_list.as_ref() {
78 match decl {
81 Declaration::Identifier { ident, .. } => {
82 if !set.insert(ident.as_ref()) {
83 unreachable!("Redeclaration of {}", ident.as_ref());
84 }
85 }
86 Declaration::Pattern(p) => {
87 for ident in p.idents() {
88 if !set.insert(ident) {
89 unreachable!("Redeclaration of {}", ident);
90 }
91 }
92 }
93 }
94 }
95 }
96 }
97 set
98 }
99
100 pub fn function_declared_names(&self) -> HashSet<&str> {
101 let mut set = HashSet::new();
102 for stmt in self.items() {
103 if let Node::FunctionDecl(decl) = stmt {
104 set.insert(decl.name());
105 }
106 }
107 set
108 }
109
110 pub fn var_declared_names(&self) -> HashSet<&str> {
111 let mut set = HashSet::new();
112 for stmt in self.items() {
113 if let Node::VarDeclList(decl_list) = stmt {
114 for decl in decl_list.as_ref() {
115 match decl {
116 Declaration::Identifier { ident, .. } => {
117 set.insert(ident.as_ref());
118 }
119 Declaration::Pattern(p) => {
120 for ident in p.idents() {
121 set.insert(ident.as_ref());
122 }
123 }
124 }
125 }
126 }
127 }
128 set
129 }
130}
131
132impl Executable for StatementList {
133 fn run(&self, context: &mut Context) -> JsResult<JsValue> {
134 let _timer = BoaProfiler::global().start_event("StatementList", "exec");
135
136 let mut obj = JsValue::default();
139 context
140 .executor()
141 .set_current_state(InterpreterState::Executing);
142
143 let strict_before = context.strict_type();
144
145 match context.strict_type() {
146 StrictType::Off if self.strict => context.set_strict(StrictType::Function),
147 StrictType::Function if !self.strict => context.set_strict_mode_off(),
148 _ => {}
149 }
150
151 for (i, item) in self.items().iter().enumerate() {
152 let val = match item.run(context) {
153 Ok(val) => val,
154 Err(e) => {
155 context.set_strict(strict_before);
156 return Err(e);
157 }
158 };
159 match context.executor().get_current_state() {
160 InterpreterState::Return => {
161 obj = val;
163 break;
164 }
165 InterpreterState::Break(_label) => {
166 break;
168 }
169 InterpreterState::Continue(_label) => {
170 break;
171 }
172 InterpreterState::Executing => {
173 }
175 }
176 if i + 1 == self.items().len() {
177 obj = val;
178 }
179 }
180
181 context.set_strict(strict_before);
182
183 Ok(obj)
184 }
185}
186
187impl<T> From<T> for StatementList
188where
189 T: Into<Box<[Node]>>,
190{
191 fn from(stm: T) -> Self {
192 Self {
193 items: stm.into(),
194 strict: false,
195 }
196 }
197}
198
199impl fmt::Display for StatementList {
200 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201 self.display(f, 0)
202 }
203}
204
205#[derive(Clone, Debug, Finalize, PartialEq)]
209pub struct RcStatementList(Rc<StatementList>);
210
211impl Deref for RcStatementList {
212 type Target = StatementList;
213 fn deref(&self) -> &Self::Target {
214 &self.0
215 }
216}
217
218impl From<StatementList> for RcStatementList {
219 #[inline]
220 fn from(statementlist: StatementList) -> Self {
221 Self(Rc::from(statementlist))
222 }
223}
224
225unsafe impl Trace for RcStatementList {
227 empty_trace!();
228}