boa_ast/function/
async_function.rs

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