1use super::{FormalParameterList, FunctionBody};
2use crate::{
3 Declaration, LinearSpan, LinearSpanIgnoreEq, Span, Spanned, block_to_string,
4 expression::{Expression, Identifier},
5 join_nodes,
6 operations::{ContainsSymbol, contains},
7 scope::{FunctionScopes, Scope},
8 visitor::{VisitWith, Visitor, VisitorMut},
9};
10use boa_interner::{Interner, ToIndentedString};
11use core::{fmt::Write as _, ops::ControlFlow};
12
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
23#[derive(Clone, Debug, PartialEq)]
24pub struct GeneratorDeclaration {
25 name: Identifier,
26 pub(crate) parameters: FormalParameterList,
27 pub(crate) body: FunctionBody,
28 pub(crate) contains_direct_eval: bool,
29
30 #[cfg_attr(feature = "serde", serde(skip))]
31 pub(crate) scopes: FunctionScopes,
32 linear_span: LinearSpanIgnoreEq,
33}
34
35impl GeneratorDeclaration {
36 #[inline]
38 #[must_use]
39 pub fn new(
40 name: Identifier,
41 parameters: FormalParameterList,
42 body: FunctionBody,
43 linear_span: LinearSpan,
44 ) -> Self {
45 let contains_direct_eval = contains(¶meters, ContainsSymbol::DirectEval)
46 || contains(&body, ContainsSymbol::DirectEval);
47 Self {
48 name,
49 parameters,
50 body,
51 contains_direct_eval,
52 scopes: FunctionScopes::default(),
53 linear_span: linear_span.into(),
54 }
55 }
56
57 #[inline]
59 #[must_use]
60 pub const fn name(&self) -> Identifier {
61 self.name
62 }
63
64 #[inline]
66 #[must_use]
67 pub const fn parameters(&self) -> &FormalParameterList {
68 &self.parameters
69 }
70
71 #[inline]
73 #[must_use]
74 pub const fn body(&self) -> &FunctionBody {
75 &self.body
76 }
77
78 #[inline]
80 #[must_use]
81 pub const fn scopes(&self) -> &FunctionScopes {
82 &self.scopes
83 }
84
85 #[inline]
87 #[must_use]
88 pub const fn linear_span(&self) -> LinearSpan {
89 self.linear_span.0
90 }
91
92 #[inline]
94 #[must_use]
95 pub const fn contains_direct_eval(&self) -> bool {
96 self.contains_direct_eval
97 }
98}
99
100impl ToIndentedString for GeneratorDeclaration {
101 fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
102 format!(
103 "function* {}({}) {}",
104 interner.resolve_expect(self.name.sym()),
105 join_nodes(interner, self.parameters.as_ref()),
106 block_to_string(&self.body.statements, interner, indentation)
107 )
108 }
109}
110
111impl VisitWith for GeneratorDeclaration {
112 fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
113 where
114 V: Visitor<'a>,
115 {
116 visitor.visit_identifier(&self.name)?;
117 visitor.visit_formal_parameter_list(&self.parameters)?;
118 visitor.visit_function_body(&self.body)
119 }
120
121 fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
122 where
123 V: VisitorMut<'a>,
124 {
125 visitor.visit_identifier_mut(&mut self.name)?;
126 visitor.visit_formal_parameter_list_mut(&mut self.parameters)?;
127 visitor.visit_function_body_mut(&mut self.body)
128 }
129}
130
131impl From<GeneratorDeclaration> for Declaration {
132 #[inline]
133 fn from(f: GeneratorDeclaration) -> Self {
134 Self::GeneratorDeclaration(f)
135 }
136}
137
138#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
147#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
148#[derive(Clone, Debug, PartialEq)]
149pub struct GeneratorExpression {
150 pub(crate) name: Option<Identifier>,
151 pub(crate) parameters: FormalParameterList,
152 pub(crate) body: FunctionBody,
153 pub(crate) has_binding_identifier: bool,
154 pub(crate) contains_direct_eval: bool,
155
156 #[cfg_attr(feature = "serde", serde(skip))]
157 pub(crate) name_scope: Option<Scope>,
158
159 #[cfg_attr(feature = "serde", serde(skip))]
160 pub(crate) scopes: FunctionScopes,
161 linear_span: LinearSpanIgnoreEq,
162
163 span: Span,
164}
165
166impl GeneratorExpression {
167 #[inline]
169 #[must_use]
170 pub fn new(
171 name: Option<Identifier>,
172 parameters: FormalParameterList,
173 body: FunctionBody,
174 linear_span: LinearSpan,
175 has_binding_identifier: bool,
176 span: Span,
177 ) -> Self {
178 let contains_direct_eval = contains(¶meters, ContainsSymbol::DirectEval)
179 || contains(&body, ContainsSymbol::DirectEval);
180 Self {
181 name,
182 parameters,
183 body,
184 has_binding_identifier,
185 name_scope: None,
186 contains_direct_eval,
187 scopes: FunctionScopes::default(),
188 linear_span: linear_span.into(),
189 span,
190 }
191 }
192
193 #[inline]
195 #[must_use]
196 pub const fn name(&self) -> Option<Identifier> {
197 self.name
198 }
199
200 #[inline]
202 #[must_use]
203 pub const fn parameters(&self) -> &FormalParameterList {
204 &self.parameters
205 }
206
207 #[inline]
209 #[must_use]
210 pub const fn body(&self) -> &FunctionBody {
211 &self.body
212 }
213
214 #[inline]
216 #[must_use]
217 pub const fn has_binding_identifier(&self) -> bool {
218 self.has_binding_identifier
219 }
220
221 #[inline]
223 #[must_use]
224 pub const fn name_scope(&self) -> Option<&Scope> {
225 self.name_scope.as_ref()
226 }
227
228 #[inline]
230 #[must_use]
231 pub const fn scopes(&self) -> &FunctionScopes {
232 &self.scopes
233 }
234
235 #[inline]
237 #[must_use]
238 pub const fn linear_span(&self) -> LinearSpan {
239 self.linear_span.0
240 }
241
242 #[inline]
244 #[must_use]
245 pub const fn contains_direct_eval(&self) -> bool {
246 self.contains_direct_eval
247 }
248}
249
250impl Spanned for GeneratorExpression {
251 #[inline]
252 fn span(&self) -> Span {
253 self.span
254 }
255}
256
257impl ToIndentedString for GeneratorExpression {
258 fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
259 let mut buf = "function*".to_owned();
260 if self.has_binding_identifier
261 && let Some(name) = self.name
262 {
263 let _ = write!(buf, " {}", interner.resolve_expect(name.sym()));
264 }
265 let _ = write!(
266 buf,
267 "({}) {}",
268 join_nodes(interner, self.parameters.as_ref()),
269 block_to_string(&self.body.statements, interner, indentation)
270 );
271
272 buf
273 }
274}
275
276impl From<GeneratorExpression> for Expression {
277 #[inline]
278 fn from(expr: GeneratorExpression) -> Self {
279 Self::GeneratorExpression(expr)
280 }
281}
282
283impl VisitWith for GeneratorExpression {
284 fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
285 where
286 V: Visitor<'a>,
287 {
288 if let Some(ident) = &self.name {
289 visitor.visit_identifier(ident)?;
290 }
291 visitor.visit_formal_parameter_list(&self.parameters)?;
292 visitor.visit_function_body(&self.body)
293 }
294
295 fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
296 where
297 V: VisitorMut<'a>,
298 {
299 if let Some(ident) = &mut self.name {
300 visitor.visit_identifier_mut(ident)?;
301 }
302 visitor.visit_formal_parameter_list_mut(&mut self.parameters)?;
303 visitor.visit_function_body_mut(&mut self.body)
304 }
305}