mirror of
https://github.com/RGBCube/serenity
synced 2025-07-28 07:07:44 +00:00
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 :^)
This commit is contained in:
parent
c7e6b65fd2
commit
1bbfaf8627
12 changed files with 503 additions and 38 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue