boa/syntax/ast/node/call/
mod.rs

1use crate::{
2    builtins::iterable,
3    exec::Executable,
4    exec::InterpreterState,
5    gc::{Finalize, Trace},
6    syntax::ast::node::{join_nodes, Node},
7    BoaProfiler, Context, JsResult, JsValue,
8};
9use std::fmt;
10
11#[cfg(feature = "deser")]
12use serde::{Deserialize, Serialize};
13
14#[cfg(test)]
15mod tests;
16
17/// Calling the function actually performs the specified actions with the indicated parameters.
18///
19/// Defining a function does not execute it. Defining it simply names the function and
20/// specifies what to do when the function is called. Functions must be in scope when they are
21/// called, but the function declaration can be hoisted. The scope of a function is the
22/// function in which it is declared (or the entire program, if it is declared at the top
23/// level).
24///
25/// More information:
26///  - [ECMAScript reference][spec]
27///  - [MDN documentation][mdn]
28///
29/// [spec]: https://tc39.es/ecma262/#prod-CallExpression
30/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions#Calling_functions
31#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
32#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
33pub struct Call {
34    expr: Box<Node>,
35    args: Box<[Node]>,
36}
37
38impl Call {
39    /// Creates a new `Call` AST node.
40    pub fn new<E, A>(expr: E, args: A) -> Self
41    where
42        E: Into<Node>,
43        A: Into<Box<[Node]>>,
44    {
45        Self {
46            expr: Box::new(expr.into()),
47            args: args.into(),
48        }
49    }
50
51    /// Gets the name of the function call.
52    pub fn expr(&self) -> &Node {
53        &self.expr
54    }
55
56    /// Retrieves the arguments passed to the function.
57    pub fn args(&self) -> &[Node] {
58        &self.args
59    }
60}
61
62impl Executable for Call {
63    fn run(&self, context: &mut Context) -> JsResult<JsValue> {
64        let _timer = BoaProfiler::global().start_event("Call", "exec");
65        let (this, func) = match self.expr() {
66            Node::GetConstField(ref get_const_field) => {
67                let mut obj = get_const_field.obj().run(context)?;
68                if !obj.is_object() {
69                    obj = JsValue::Object(obj.to_object(context)?);
70                }
71                (
72                    obj.clone(),
73                    obj.get_field(get_const_field.field(), context)?,
74                )
75            }
76            Node::GetField(ref get_field) => {
77                let mut obj = get_field.obj().run(context)?;
78                if !obj.is_object() {
79                    obj = JsValue::Object(obj.to_object(context)?);
80                }
81                let field = get_field.field().run(context)?;
82                (
83                    obj.clone(),
84                    obj.get_field(field.to_property_key(context)?, context)?,
85                )
86            }
87            _ => (
88                // 'this' binding should come from the function's self-contained environment
89                context.global_object().into(),
90                self.expr().run(context)?,
91            ),
92        };
93        let mut v_args = Vec::with_capacity(self.args().len());
94        for arg in self.args() {
95            if let Node::Spread(ref x) = arg {
96                let val = x.run(context)?;
97                let iterator_record = iterable::get_iterator(&val, context)?;
98                loop {
99                    let next = iterator_record.next(context)?;
100                    if next.done {
101                        break;
102                    }
103                    let next_value = next.value;
104                    v_args.push(next_value);
105                }
106                break; // after spread we don't accept any new arguments
107            } else {
108                v_args.push(arg.run(context)?);
109            }
110        }
111
112        // execute the function call itself
113        let fnct_result = context.call(&func, &this, &v_args);
114
115        // unset the early return flag
116        context
117            .executor()
118            .set_current_state(InterpreterState::Executing);
119
120        fnct_result
121    }
122}
123
124impl fmt::Display for Call {
125    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126        write!(f, "{}(", self.expr)?;
127        join_nodes(f, &self.args)?;
128        f.write_str(")")
129    }
130}
131
132impl From<Call> for Node {
133    fn from(call: Call) -> Self {
134        Self::Call(call)
135    }
136}