1use std::ops::ControlFlow;
2
3use boa_interner::{Interner, Sym, ToIndentedString};
4
5use crate::{
6 ModuleItemList, StatementList,
7 scope::Scope,
8 scope_analyzer::{
9 EvalDeclarationBindings, analyze_binding_escapes, collect_bindings,
10 eval_declaration_instantiation_scope, optimize_scope_indices,
11 },
12 visitor::{VisitWith, Visitor, VisitorMut},
13};
14
15#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22#[derive(Clone, Debug, Default)]
23pub struct Script {
24 statements: StatementList,
25}
26
27impl Script {
28 #[must_use]
30 pub const fn new(statements: StatementList) -> Self {
31 Self { statements }
32 }
33
34 #[must_use]
36 pub const fn statements(&self) -> &StatementList {
37 &self.statements
38 }
39
40 pub fn statements_mut(&mut self) -> &mut StatementList {
42 &mut self.statements
43 }
44
45 #[inline]
47 #[must_use]
48 pub const fn strict(&self) -> bool {
49 self.statements.strict()
50 }
51
52 pub fn analyze_scope(
57 &mut self,
58 scope: &Scope,
59 interner: &Interner,
60 ) -> Result<(), &'static str> {
61 collect_bindings(self, self.strict(), false, scope, interner)?;
62 analyze_binding_escapes(self, false, scope.clone(), interner)?;
63 optimize_scope_indices(self, scope);
64 Ok(())
65 }
66
67 pub fn analyze_scope_eval(
73 &mut self,
74 strict: bool,
75 variable_scope: &Scope,
76 lexical_scope: &Scope,
77 annex_b_function_names: &[Sym],
78 interner: &Interner,
79 ) -> Result<EvalDeclarationBindings, String> {
80 let bindings = eval_declaration_instantiation_scope(
81 self,
82 strict,
83 variable_scope,
84 lexical_scope,
85 annex_b_function_names,
86 interner,
87 )?;
88
89 if let Err(reason) = collect_bindings(self, strict, true, lexical_scope, interner) {
90 return Err(format!("Failed to analyze scope: {reason}"));
91 }
92 if let Err(reason) = analyze_binding_escapes(self, true, lexical_scope.clone(), interner) {
93 return Err(format!("Failed to analyze scope: {reason}"));
94 }
95
96 variable_scope.escape_all_bindings();
97 lexical_scope.escape_all_bindings();
98 variable_scope.reorder_binding_indices();
99 lexical_scope.reorder_binding_indices();
100 optimize_scope_indices(self, lexical_scope);
101
102 Ok(bindings)
103 }
104}
105
106impl VisitWith for Script {
107 fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
108 where
109 V: Visitor<'a>,
110 {
111 self.statements.visit_with(visitor)
112 }
113
114 fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
115 where
116 V: VisitorMut<'a>,
117 {
118 self.statements.visit_with_mut(visitor)
119 }
120}
121
122impl ToIndentedString for Script {
123 fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
124 self.statements.to_indented_string(interner, indentation)
125 }
126}
127
128impl PartialEq for Script {
129 fn eq(&self, other: &Self) -> bool {
130 self.statements == other.statements
131 }
132}
133
134#[cfg(feature = "arbitrary")]
135impl<'a> arbitrary::Arbitrary<'a> for Script {
136 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
137 let statements = StatementList::arbitrary(u)?;
138 Ok(Self { statements })
139 }
140}
141
142#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
149#[derive(Clone, Debug, Default, PartialEq)]
150pub struct Module {
151 pub(crate) items: ModuleItemList,
152
153 #[cfg_attr(feature = "serde", serde(skip))]
154 pub(crate) scope: Scope,
155}
156
157impl Module {
158 #[must_use]
160 pub fn new(items: ModuleItemList) -> Self {
161 Self {
162 items,
163 scope: Scope::default(),
164 }
165 }
166
167 #[must_use]
169 pub const fn items(&self) -> &ModuleItemList {
170 &self.items
171 }
172
173 #[inline]
175 #[must_use]
176 pub const fn scope(&self) -> &Scope {
177 &self.scope
178 }
179
180 pub fn analyze_scope(
185 &mut self,
186 scope: &Scope,
187 interner: &Interner,
188 ) -> Result<(), &'static str> {
189 collect_bindings(self, true, false, scope, interner)?;
190 analyze_binding_escapes(self, false, scope.clone(), interner)?;
191 optimize_scope_indices(self, &self.scope.clone());
192
193 Ok(())
194 }
195}
196
197impl VisitWith for Module {
198 fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
199 where
200 V: Visitor<'a>,
201 {
202 self.items.visit_with(visitor)
203 }
204
205 fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
206 where
207 V: VisitorMut<'a>,
208 {
209 self.items.visit_with_mut(visitor)
210 }
211}