boa_ast/function/
arrow_function.rs1use 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#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
24#[derive(Clone, Debug, PartialEq)]
25pub struct ArrowFunction {
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 span: Span,
35}
36
37impl ArrowFunction {
38 #[inline]
40 #[must_use]
41 pub fn new(
42 name: Option<Identifier>,
43 parameters: FormalParameterList,
44 body: FunctionBody,
45 linear_span: LinearSpan,
46 span: Span,
47 ) -> Self {
48 let contains_direct_eval = contains(¶meters, 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 span,
58 }
59 }
60
61 #[inline]
63 #[must_use]
64 pub const fn name(&self) -> Option<Identifier> {
65 self.name
66 }
67
68 #[inline]
70 pub fn set_name(&mut self, name: Option<Identifier>) {
71 self.name = name;
72 }
73
74 #[inline]
76 #[must_use]
77 pub const fn parameters(&self) -> &FormalParameterList {
78 &self.parameters
79 }
80
81 #[inline]
83 #[must_use]
84 pub const fn body(&self) -> &FunctionBody {
85 &self.body
86 }
87
88 #[inline]
90 #[must_use]
91 pub const fn scopes(&self) -> &FunctionScopes {
92 &self.scopes
93 }
94
95 #[inline]
97 #[must_use]
98 pub const fn linear_span(&self) -> LinearSpan {
99 self.linear_span.0
100 }
101
102 #[inline]
104 #[must_use]
105 pub const fn contains_direct_eval(&self) -> bool {
106 self.contains_direct_eval
107 }
108}
109
110impl Spanned for ArrowFunction {
111 #[inline]
112 fn span(&self) -> Span {
113 self.span
114 }
115}
116
117impl ToIndentedString for ArrowFunction {
118 fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
119 let mut buf = format!("({}", join_nodes(interner, self.parameters.as_ref()));
120 if self.body().statements().is_empty() {
121 buf.push_str(") => {}");
122 } else {
123 let _ = write!(
124 buf,
125 ") => {{\n{}{}}}",
126 self.body.to_indented_string(interner, indentation + 1),
127 " ".repeat(indentation)
128 );
129 }
130 buf
131 }
132}
133
134impl From<ArrowFunction> for Expression {
135 fn from(decl: ArrowFunction) -> Self {
136 Self::ArrowFunction(decl)
137 }
138}
139
140impl VisitWith for ArrowFunction {
141 fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
142 where
143 V: Visitor<'a>,
144 {
145 if let Some(ident) = &self.name {
146 visitor.visit_identifier(ident)?;
147 }
148 visitor.visit_formal_parameter_list(&self.parameters)?;
149 visitor.visit_function_body(&self.body)
150 }
151
152 fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
153 where
154 V: VisitorMut<'a>,
155 {
156 if let Some(ident) = &mut self.name {
157 visitor.visit_identifier_mut(ident)?;
158 }
159 visitor.visit_formal_parameter_list_mut(&mut self.parameters)?;
160 visitor.visit_function_body_mut(&mut self.body)
161 }
162}