From 0dc4e722e6e5996732e099c57013794c3d219d97 Mon Sep 17 00:00:00 2001 From: Hendi Date: Wed, 7 Jul 2021 22:53:32 +0200 Subject: [PATCH] LibJS: Make FunctionExpression more spec-compliant --- Userland/Libraries/LibJS/AST.cpp | 16 +++++++++++++++- Userland/Libraries/LibJS/AST.h | 6 +++++- Userland/Libraries/LibJS/Runtime/VM.cpp | 2 ++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Userland/Libraries/LibJS/AST.cpp b/Userland/Libraries/LibJS/AST.cpp index b0d95fbcaaa..06f548bb076 100644 --- a/Userland/Libraries/LibJS/AST.cpp +++ b/Userland/Libraries/LibJS/AST.cpp @@ -99,10 +99,24 @@ Value FunctionDeclaration::execute(Interpreter& interpreter, GlobalObject&) cons return {}; } +// 15.2.5 Runtime Semantics: InstantiateOrdinaryFunctionExpression, https://tc39.es/ecma262/#sec-runtime-semantics-instantiateordinaryfunctionexpression Value FunctionExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; - return OrdinaryFunctionObject::create(global_object, name(), body(), parameters(), function_length(), interpreter.lexical_environment(), kind(), is_strict_mode() || interpreter.vm().in_strict_mode(), is_arrow_function()); + auto* func_env = interpreter.lexical_environment(); + bool has_identifier = !name().is_empty() && !is_auto_renamed(); + + if (has_identifier) { + func_env = interpreter.heap().allocate(global_object, func_env); + func_env->create_immutable_binding(global_object, name(), false); + } + + auto closure = OrdinaryFunctionObject::create(global_object, name(), body(), parameters(), function_length(), func_env, kind(), is_strict_mode() || interpreter.vm().in_strict_mode(), is_arrow_function()); + + if (has_identifier) + func_env->initialize_binding(global_object, name(), closure); + + return closure; } Value ExpressionStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const diff --git a/Userland/Libraries/LibJS/AST.h b/Userland/Libraries/LibJS/AST.h index 7b94fe38af3..2e5faf424f5 100644 --- a/Userland/Libraries/LibJS/AST.h +++ b/Userland/Libraries/LibJS/AST.h @@ -327,16 +327,20 @@ public: if (m_cannot_auto_rename) return; m_cannot_auto_rename = true; - if (name().is_empty()) + if (name().is_empty()) { set_name(move(new_name)); + m_is_auto_renamed = true; + } } bool cannot_auto_rename() const { return m_cannot_auto_rename; } + bool is_auto_renamed() const { return m_is_auto_renamed; } void set_cannot_auto_rename() { m_cannot_auto_rename = true; } virtual void generate_bytecode(Bytecode::Generator&) const override; private: bool m_cannot_auto_rename { false }; + bool m_is_auto_renamed { false }; }; class ErrorExpression final : public Expression { diff --git a/Userland/Libraries/LibJS/Runtime/VM.cpp b/Userland/Libraries/LibJS/Runtime/VM.cpp index fe04633b22c..4aeaa79df97 100644 --- a/Userland/Libraries/LibJS/Runtime/VM.cpp +++ b/Userland/Libraries/LibJS/Runtime/VM.cpp @@ -384,6 +384,8 @@ Value VM::get_variable(const FlyString& name, GlobalObject& global_object) return {}; if (possible_match.has_value()) return possible_match.value().value; + if (environment->has_binding(name)) + return environment->get_binding_value(global_object, name, false); } }