boa/syntax/ast/node/declaration/function_decl/
mod.rs1use 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#[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 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 pub fn name(&self) -> &str {
57 &self.name
58 }
59
60 pub fn parameters(&self) -> &[FormalParameter] {
62 &self.parameters
63 }
64
65 pub fn body(&self) -> &StatementList {
67 &self.body
68 }
69
70 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}