Skip to main content

boa_ast/function/
async_arrow_function.rs

1use super::{FormalParameterList, FunctionBody};
2use crate::operations::{ContainsSymbol, contains};
3use crate::scope::FunctionScopes;
4use crate::visitor::{VisitWith, Visitor, VisitorMut};
5use crate::{LinearSpan, LinearSpanIgnoreEq, Span, Spanned};
6use crate::{
7    expression::{Expression, Identifier},
8    join_nodes,
9};
10use boa_interner::{Interner, ToIndentedString};
11use core::{fmt::Write as _, ops::ControlFlow};
12
13/// An async arrow function expression, as defined by the [spec].
14///
15/// An [async arrow function][mdn] expression is a syntactically compact alternative to a regular function
16/// expression. Arrow function expressions are ill suited as methods, and they cannot be used as
17/// constructors. Arrow functions cannot be used as constructors and will throw an error when
18/// used with new.
19///
20/// [spec]: https://tc39.es/ecma262/#prod-AsyncArrowFunction
21/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
24#[derive(Clone, Debug, PartialEq)]
25pub struct AsyncArrowFunction {
26    pub(crate) name: Option<Identifier>,
27    pub(crate) parameters: FormalParameterList,
28    pub(crate) body: FunctionBody,
29    pub(crate) contains_direct_eval: bool,
30
31    #[cfg_attr(feature = "serde", serde(skip))]
32    pub(crate) scopes: FunctionScopes,
33    linear_span: LinearSpanIgnoreEq,
34
35    span: Span,
36}
37
38impl AsyncArrowFunction {
39    /// Creates a new `AsyncArrowFunction` AST Expression.
40    #[inline]
41    #[must_use]
42    pub fn new(
43        name: Option<Identifier>,
44        parameters: FormalParameterList,
45        body: FunctionBody,
46        linear_span: LinearSpan,
47        span: Span,
48    ) -> Self {
49        let contains_direct_eval = contains(&parameters, ContainsSymbol::DirectEval)
50            || contains(&body, ContainsSymbol::DirectEval);
51        Self {
52            name,
53            parameters,
54            body,
55            contains_direct_eval,
56            scopes: FunctionScopes::default(),
57            linear_span: linear_span.into(),
58            span,
59        }
60    }
61
62    /// Gets the name of the async arrow function.
63    #[inline]
64    #[must_use]
65    pub const fn name(&self) -> Option<Identifier> {
66        self.name
67    }
68
69    /// Sets the name of the async arrow function.
70    #[inline]
71    pub fn set_name(&mut self, name: Option<Identifier>) {
72        self.name = name;
73    }
74
75    /// Gets the list of parameters of the async arrow function.
76    #[inline]
77    #[must_use]
78    pub const fn parameters(&self) -> &FormalParameterList {
79        &self.parameters
80    }
81
82    /// Gets the body of the async arrow function.
83    #[inline]
84    #[must_use]
85    pub const fn body(&self) -> &FunctionBody {
86        &self.body
87    }
88
89    /// Returns the scopes of the async arrow function.
90    #[inline]
91    #[must_use]
92    pub const fn scopes(&self) -> &FunctionScopes {
93        &self.scopes
94    }
95
96    /// Gets linear span of the function declaration.
97    #[inline]
98    #[must_use]
99    pub const fn linear_span(&self) -> LinearSpan {
100        self.linear_span.0
101    }
102
103    /// Returns `true` if the function declaration contains a direct call to `eval`.
104    #[inline]
105    #[must_use]
106    pub const fn contains_direct_eval(&self) -> bool {
107        self.contains_direct_eval
108    }
109}
110
111impl Spanned for AsyncArrowFunction {
112    #[inline]
113    fn span(&self) -> Span {
114        self.span
115    }
116}
117
118impl ToIndentedString for AsyncArrowFunction {
119    fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
120        let mut buf = format!("async ({}", join_nodes(interner, self.parameters.as_ref()));
121        if self.body().statements().is_empty() {
122            buf.push_str(") => {}");
123        } else {
124            let _ = write!(
125                buf,
126                ") => {{\n{}{}}}",
127                self.body.to_indented_string(interner, indentation + 1),
128                "    ".repeat(indentation)
129            );
130        }
131        buf
132    }
133}
134
135impl From<AsyncArrowFunction> for Expression {
136    fn from(decl: AsyncArrowFunction) -> Self {
137        Self::AsyncArrowFunction(decl)
138    }
139}
140
141impl VisitWith for AsyncArrowFunction {
142    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
143    where
144        V: Visitor<'a>,
145    {
146        if let Some(ident) = &self.name {
147            visitor.visit_identifier(ident)?;
148        }
149        visitor.visit_formal_parameter_list(&self.parameters)?;
150        visitor.visit_function_body(&self.body)
151    }
152
153    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
154    where
155        V: VisitorMut<'a>,
156    {
157        if let Some(ident) = &mut self.name {
158            visitor.visit_identifier_mut(ident)?;
159        }
160        visitor.visit_formal_parameter_list_mut(&mut self.parameters)?;
161        visitor.visit_function_body_mut(&mut self.body)
162    }
163}