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