boa_ast/expression/
call.rs

1use crate::visitor::{VisitWith, Visitor, VisitorMut};
2use crate::{Span, Spanned, join_nodes};
3use boa_interner::{Interner, ToInternedString};
4use core::ops::ControlFlow;
5
6use super::Expression;
7
8/// Calling the function actually performs the specified actions with the indicated parameters.
9///
10/// Defining a function does not execute it. Defining it simply names the function and
11/// specifies what to do when the function is called. Functions must be in scope when they are
12/// called, but the function declaration can be hoisted. The scope of a function is the
13/// function in which it is declared (or the entire program, if it is declared at the top
14/// level).
15///
16/// More information:
17///  - [ECMAScript reference][spec]
18///  - [MDN documentation][mdn]
19///
20/// [spec]: https://tc39.es/ecma262/#prod-CallExpression
21/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions#Calling_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 Call {
26    function: Box<Expression>,
27    args: Box<[Expression]>,
28    span: Span,
29}
30
31impl Call {
32    /// Creates a new `Call` AST Expression.
33    #[inline]
34    #[must_use]
35    pub fn new(function: Expression, args: Box<[Expression]>, span: Span) -> Self {
36        Self {
37            function: Box::new(function),
38            args,
39            span,
40        }
41    }
42
43    /// Gets the target function of this call expression.
44    #[inline]
45    #[must_use]
46    pub const fn function(&self) -> &Expression {
47        &self.function
48    }
49
50    /// Retrieves the arguments passed to the function.
51    #[inline]
52    #[must_use]
53    pub const fn args(&self) -> &[Expression] {
54        &self.args
55    }
56}
57
58impl Spanned for Call {
59    #[inline]
60    fn span(&self) -> Span {
61        self.span
62    }
63}
64
65impl ToInternedString for Call {
66    #[inline]
67    fn to_interned_string(&self, interner: &Interner) -> String {
68        format!(
69            "{}({})",
70            self.function.to_interned_string(interner),
71            join_nodes(interner, &self.args)
72        )
73    }
74}
75
76impl From<Call> for Expression {
77    #[inline]
78    fn from(call: Call) -> Self {
79        Self::Call(call)
80    }
81}
82
83impl VisitWith for Call {
84    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
85    where
86        V: Visitor<'a>,
87    {
88        visitor.visit_expression(&self.function)?;
89        for expr in &*self.args {
90            visitor.visit_expression(expr)?;
91        }
92        ControlFlow::Continue(())
93    }
94
95    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
96    where
97        V: VisitorMut<'a>,
98    {
99        visitor.visit_expression_mut(&mut self.function)?;
100        for expr in &mut *self.args {
101            visitor.visit_expression_mut(expr)?;
102        }
103        ControlFlow::Continue(())
104    }
105}
106
107/// The `super` keyword is used to access and call functions on an object's parent.
108///
109/// More information:
110///  - [ECMAScript reference][spec]
111///  - [MDN documentation][mdn]
112///
113/// [spec]: https://tc39.es/ecma262/#prod-SuperCall
114/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super
115#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
116#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
117#[derive(Clone, Debug, PartialEq)]
118pub struct SuperCall {
119    args: Box<[Expression]>,
120    span: Span,
121}
122
123impl SuperCall {
124    /// Creates a new `SuperCall` AST node.
125    pub fn new<A>(args: A, span: Span) -> Self
126    where
127        A: Into<Box<[Expression]>>,
128    {
129        Self {
130            args: args.into(),
131            span,
132        }
133    }
134
135    /// Retrieves the arguments of the super call.
136    #[must_use]
137    pub const fn arguments(&self) -> &[Expression] {
138        &self.args
139    }
140}
141
142impl Spanned for SuperCall {
143    #[inline]
144    fn span(&self) -> Span {
145        self.span
146    }
147}
148
149impl ToInternedString for SuperCall {
150    #[inline]
151    fn to_interned_string(&self, interner: &Interner) -> String {
152        format!("super({})", join_nodes(interner, &self.args))
153    }
154}
155
156impl From<SuperCall> for Expression {
157    #[inline]
158    fn from(call: SuperCall) -> Self {
159        Self::SuperCall(call)
160    }
161}
162
163impl VisitWith for SuperCall {
164    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
165    where
166        V: Visitor<'a>,
167    {
168        for expr in &*self.args {
169            visitor.visit_expression(expr)?;
170        }
171        ControlFlow::Continue(())
172    }
173
174    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
175    where
176        V: VisitorMut<'a>,
177    {
178        for expr in &mut *self.args {
179            visitor.visit_expression_mut(expr)?;
180        }
181        ControlFlow::Continue(())
182    }
183}
184
185/// The `import()` syntax, commonly called dynamic import, is a function-like expression that allows
186/// loading an ECMAScript module asynchronously and dynamically into a potentially non-module
187/// environment.
188///
189/// More information:
190///  - [ECMAScript reference][spec]
191///  - [MDN documentation][mdn]
192///
193/// [spec]: https://tc39.es/ecma262/#prod-ImportCall
194/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import
195#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
196#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
197#[derive(Clone, Debug, PartialEq)]
198pub struct ImportCall {
199    arg: Box<Expression>,
200    span: Span,
201}
202
203impl ImportCall {
204    /// Creates a new `ImportCall` AST node.
205    pub fn new<A>(arg: A, span: Span) -> Self
206    where
207        A: Into<Expression>,
208    {
209        Self {
210            arg: Box::new(arg.into()),
211            span,
212        }
213    }
214
215    /// Retrieves the single argument of the import call.
216    #[must_use]
217    pub const fn argument(&self) -> &Expression {
218        &self.arg
219    }
220}
221
222impl Spanned for ImportCall {
223    #[inline]
224    fn span(&self) -> Span {
225        self.span
226    }
227}
228
229impl ToInternedString for ImportCall {
230    #[inline]
231    fn to_interned_string(&self, interner: &Interner) -> String {
232        format!("import({})", self.arg.to_interned_string(interner))
233    }
234}
235
236impl From<ImportCall> for Expression {
237    #[inline]
238    fn from(call: ImportCall) -> Self {
239        Self::ImportCall(call)
240    }
241}
242
243impl VisitWith for ImportCall {
244    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
245    where
246        V: Visitor<'a>,
247    {
248        visitor.visit_expression(&self.arg)
249    }
250
251    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
252    where
253        V: VisitorMut<'a>,
254    {
255        visitor.visit_expression_mut(&mut self.arg)
256    }
257}