diff options
author | Ali Mohammad Pur <ali.mpfard@gmail.com> | 2022-02-12 19:48:45 +0330 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2022-02-13 14:41:33 +0000 |
commit | 1bbfaf8627112438ee177d4b0986970755e958bb (patch) | |
tree | 2cb98a6219120904fddc34c0ea8c9a00a8af7b22 /Userland/Libraries/LibJS/Runtime | |
parent | c7e6b65fd299e60385179f40a2cadee1fc28f77e (diff) | |
download | serenity-1bbfaf8627112438ee177d4b0986970755e958bb.zip |
LibJS: More properly implement scoping rules in bytecode codegen
Now we emit CreateVariable and SetVariable with the appropriate
initialization/environment modes, much closer to the spec.
This makes a whole lot of things like let/const variables, function
and variable hoisting and some other things work :^)
Diffstat (limited to 'Userland/Libraries/LibJS/Runtime')
5 files changed, 21 insertions, 12 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.cpp b/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.cpp index 214f1a28c6..17e126ffd0 100644 --- a/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.cpp +++ b/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.cpp @@ -196,15 +196,21 @@ ThrowCompletionOr<bool> DeclarativeEnvironment::delete_binding(GlobalObject&, Fl return true; } -void DeclarativeEnvironment::initialize_or_set_mutable_binding(Badge<ScopeNode>, GlobalObject& global_object, FlyString const& name, Value value) +ThrowCompletionOr<void> DeclarativeEnvironment::initialize_or_set_mutable_binding(GlobalObject& global_object, FlyString const& name, Value value) { auto it = m_names.find(name); VERIFY(it != m_names.end()); auto& binding = m_bindings[it->value]; if (!binding.initialized) - MUST(initialize_binding(global_object, name, value)); + TRY(initialize_binding(global_object, name, value)); else - MUST(set_mutable_binding(global_object, name, value, false)); + TRY(set_mutable_binding(global_object, name, value, false)); + return {}; +} + +void DeclarativeEnvironment::initialize_or_set_mutable_binding(Badge<ScopeNode>, GlobalObject& global_object, FlyString const& name, Value value) +{ + MUST(initialize_or_set_mutable_binding(global_object, name, value)); } Vector<String> DeclarativeEnvironment::bindings() const diff --git a/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.h b/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.h index 934c14400d..4da324a0d8 100644 --- a/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.h +++ b/Userland/Libraries/LibJS/Runtime/DeclarativeEnvironment.h @@ -31,6 +31,7 @@ public: virtual ThrowCompletionOr<bool> delete_binding(GlobalObject&, FlyString const& name) override; void initialize_or_set_mutable_binding(Badge<ScopeNode>, GlobalObject& global_object, FlyString const& name, Value value); + ThrowCompletionOr<void> initialize_or_set_mutable_binding(GlobalObject& global_object, FlyString const& name, Value value); // This is not a method defined in the spec! Do not use this in any LibJS (or other spec related) code. [[nodiscard]] Vector<String> bindings() const; diff --git a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp index 65e29633a0..17423a6cae 100644 --- a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp @@ -542,14 +542,16 @@ ThrowCompletionOr<void> ECMAScriptFunctionObject::function_declaration_instantia if (!scope_body) return {}; - scope_body->for_each_lexically_scoped_declaration([&](Declaration const& declaration) { - declaration.for_each_bound_name([&](auto const& name) { - if (declaration.is_constant_declaration()) - MUST(lex_environment->create_immutable_binding(global_object(), name, true)); - else - MUST(lex_environment->create_mutable_binding(global_object(), name, false)); + if (!Bytecode::Interpreter::current()) { + scope_body->for_each_lexically_scoped_declaration([&](Declaration const& declaration) { + declaration.for_each_bound_name([&](auto const& name) { + if (declaration.is_constant_declaration()) + MUST(lex_environment->create_immutable_binding(global_object(), name, true)); + else + MUST(lex_environment->create_mutable_binding(global_object(), name, false)); + }); }); - }); + } auto* private_environment = callee_context.private_environment; for (auto& declaration : functions_to_initialize) { diff --git a/Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp b/Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp index 78d35700cd..6644e0092d 100644 --- a/Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp @@ -97,7 +97,7 @@ ThrowCompletionOr<Value> GeneratorObject::next_impl(VM& vm, GlobalObject& global VERIFY(!m_generating_function->bytecode_executable()->basic_blocks.find_if([next_block](auto& block) { return block == next_block; }).is_end()); // Restore the snapshot registers - bytecode_interpreter->enter_frame(m_frame); + bytecode_interpreter->enter_frame(*m_frame); // Temporarily switch to the captured execution context TRY(vm.push_execution_context(m_execution_context, global_object)); diff --git a/Userland/Libraries/LibJS/Runtime/GeneratorObject.h b/Userland/Libraries/LibJS/Runtime/GeneratorObject.h index 29ea61ff4d..dd84506528 100644 --- a/Userland/Libraries/LibJS/Runtime/GeneratorObject.h +++ b/Userland/Libraries/LibJS/Runtime/GeneratorObject.h @@ -29,7 +29,7 @@ private: ExecutionContext m_execution_context; ECMAScriptFunctionObject* m_generating_function { nullptr }; Value m_previous_value; - Bytecode::RegisterWindow m_frame; + Optional<Bytecode::RegisterWindow> m_frame; bool m_done { false }; }; |