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

1use crate::{
2    builtins::iterable,
3    exec::Executable,
4    gc::{Finalize, Trace},
5    syntax::ast::node::{Call, Node},
6    value::JsValue,
7    BoaProfiler, Context, JsResult,
8};
9use std::fmt;
10
11#[cfg(feature = "deser")]
12use serde::{Deserialize, Serialize};
13
14#[cfg(test)]
15mod tests;
16
17/// The `new` operator lets developers create an instance of a user-defined object type or of
18/// one of the built-in object types that has a constructor function.
19///
20/// The new keyword does the following things:
21///  - Creates a blank, plain JavaScript object;
22///  - Links (sets the constructor of) this object to another object;
23///  - Passes the newly created object from Step 1 as the this context;
24///  - Returns this if the function doesn't return its own object.
25///
26/// More information:
27///  - [ECMAScript reference][spec]
28///  - [MDN documentation][mdn]
29///
30/// [spec]: https://tc39.es/ecma262/#prod-NewExpression
31/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new
32#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
33#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
34pub struct New {
35    call: Call,
36}
37
38impl New {
39    /// Gets the name of the function call.
40    pub fn expr(&self) -> &Node {
41        self.call.expr()
42    }
43
44    /// Retrieves the arguments passed to the function.
45    pub fn args(&self) -> &[Node] {
46        self.call.args()
47    }
48}
49
50impl Executable for New {
51    fn run(&self, context: &mut Context) -> JsResult<JsValue> {
52        let _timer = BoaProfiler::global().start_event("New", "exec");
53
54        let func_object = self.expr().run(context)?;
55        let mut v_args = Vec::with_capacity(self.args().len());
56        for arg in self.args() {
57            if let Node::Spread(ref x) = arg {
58                let val = x.run(context)?;
59                let iterator_record = iterable::get_iterator(&val, context)?;
60                loop {
61                    let next = iterator_record.next(context)?;
62                    if next.done {
63                        break;
64                    }
65                    let next_value = next.value;
66                    v_args.push(next_value);
67                }
68                break; // after spread we don't accept any new arguments
69            } else {
70                v_args.push(arg.run(context)?);
71            }
72        }
73
74        match func_object {
75            JsValue::Object(ref object) => {
76                object.construct(&v_args, &object.clone().into(), context)
77            }
78            _ => context
79                .throw_type_error(format!("{} is not a constructor", self.expr().to_string(),)),
80        }
81    }
82}
83
84impl From<Call> for New {
85    fn from(call: Call) -> Self {
86        Self { call }
87    }
88}
89
90impl fmt::Display for New {
91    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92        write!(f, "new {}", self.call)
93    }
94}
95
96impl From<New> for Node {
97    fn from(new: New) -> Self {
98        Self::New(new)
99    }
100}