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

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