Skip to main content

boa_ast/function/
async_generator.rs

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