boa/syntax/ast/node/declaration/function_expr/
mod.rs

1use crate::{
2    builtins::function::FunctionFlags,
3    exec::Executable,
4    gc::{Finalize, Trace},
5    syntax::ast::node::{join_nodes, FormalParameter, Node, StatementList},
6    Context, JsResult, JsValue,
7};
8use std::fmt;
9
10#[cfg(feature = "deser")]
11use serde::{Deserialize, Serialize};
12
13/// The `function` expression defines a function with the specified parameters.
14///
15/// A function created with a function expression is a `Function` object and has all the
16/// properties, methods and behavior of `Function`.
17///
18/// A function can also be created using a declaration (see function expression).
19///
20/// By default, functions return `undefined`. To return any other value, the function must have
21/// a return statement that specifies the value to return.
22///
23/// More information:
24///  - [ECMAScript reference][spec]
25///  - [MDN documentation][mdn]
26///
27/// [spec]: https://tc39.es/ecma262/#sec-terms-and-definitions-function
28/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function
29#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
30#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
31pub struct FunctionExpr {
32    name: Option<Box<str>>,
33    parameters: Box<[FormalParameter]>,
34    body: StatementList,
35}
36
37impl FunctionExpr {
38    /// Creates a new function expression
39    pub(in crate::syntax) fn new<N, P, B>(name: N, parameters: P, body: B) -> Self
40    where
41        N: Into<Option<Box<str>>>,
42        P: Into<Box<[FormalParameter]>>,
43        B: Into<StatementList>,
44    {
45        Self {
46            name: name.into(),
47            parameters: parameters.into(),
48            body: body.into(),
49        }
50    }
51
52    /// Gets the name of the function declaration.
53    pub fn name(&self) -> Option<&str> {
54        self.name.as_ref().map(Box::as_ref)
55    }
56
57    /// Gets the list of parameters of the function declaration.
58    pub fn parameters(&self) -> &[FormalParameter] {
59        &self.parameters
60    }
61
62    /// Gets the body of the function declaration.
63    pub fn body(&self) -> &StatementList {
64        &self.body
65    }
66
67    /// Implements the display formatting with indentation.
68    pub(in crate::syntax::ast::node) fn display(
69        &self,
70        f: &mut fmt::Formatter<'_>,
71        indentation: usize,
72    ) -> fmt::Result {
73        f.write_str("function")?;
74        if let Some(ref name) = self.name {
75            write!(f, " {}", name)?;
76        }
77        f.write_str("(")?;
78        join_nodes(f, &self.parameters)?;
79        f.write_str(") ")?;
80        self.display_block(f, indentation)
81    }
82
83    /// Displays the function's body. This includes the curly braces at the start and end.
84    /// This will not indent the first brace, but will indent the last brace.
85    pub(in crate::syntax::ast::node) fn display_block(
86        &self,
87        f: &mut fmt::Formatter<'_>,
88        indentation: usize,
89    ) -> fmt::Result {
90        if self.body().items().is_empty() {
91            f.write_str("{}")
92        } else {
93            f.write_str("{\n")?;
94            self.body.display(f, indentation + 1)?;
95            write!(f, "{}}}", "    ".repeat(indentation))
96        }
97    }
98}
99
100impl Executable for FunctionExpr {
101    fn run(&self, context: &mut Context) -> JsResult<JsValue> {
102        let val = context.create_function(
103            self.name().unwrap_or(""),
104            self.parameters().to_vec(),
105            self.body().clone(),
106            FunctionFlags::CONSTRUCTABLE,
107        )?;
108
109        Ok(val)
110    }
111}
112
113impl fmt::Display for FunctionExpr {
114    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115        self.display(f, 0)
116    }
117}
118
119impl From<FunctionExpr> for Node {
120    fn from(expr: FunctionExpr) -> Self {
121        Self::FunctionExpr(expr)
122    }
123}