1use 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#[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 #[inline]
41 #[must_use]
42 pub fn new(name: Identifier, parameters: FormalParameterList, body: FunctionBody) -> Self {
43 let contains_direct_eval = contains(¶meters, 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 #[inline]
56 #[must_use]
57 pub const fn name(&self) -> Identifier {
58 self.name
59 }
60
61 #[inline]
63 #[must_use]
64 pub const fn parameters(&self) -> &FormalParameterList {
65 &self.parameters
66 }
67
68 #[inline]
70 #[must_use]
71 pub const fn body(&self) -> &FunctionBody {
72 &self.body
73 }
74
75 #[inline]
77 #[must_use]
78 pub const fn scopes(&self) -> &FunctionScopes {
79 &self.scopes
80 }
81
82 #[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#[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 #[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(¶meters, 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 #[inline]
178 #[must_use]
179 pub const fn name(&self) -> Option<Identifier> {
180 self.name
181 }
182
183 #[inline]
185 #[must_use]
186 pub const fn parameters(&self) -> &FormalParameterList {
187 &self.parameters
188 }
189
190 #[inline]
192 #[must_use]
193 pub const fn body(&self) -> &FunctionBody {
194 &self.body
195 }
196
197 #[inline]
199 #[must_use]
200 pub const fn has_binding_identifier(&self) -> bool {
201 self.has_binding_identifier
202 }
203
204 #[inline]
206 #[must_use]
207 pub const fn name_scope(&self) -> Option<&Scope> {
208 self.name_scope.as_ref()
209 }
210
211 #[inline]
213 #[must_use]
214 pub const fn scopes(&self) -> &FunctionScopes {
215 &self.scopes
216 }
217
218 #[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}