1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 05:47:34 +00:00

LibJS: Add using declaration support, RAII like operation in js

In this patch only top level and not the more complicated for loop using
statements are supported. Also, as noted in the latest meeting of tc39
async parts of the spec are not stage 3 thus not included.
This commit is contained in:
davidot 2022-12-20 22:09:57 +01:00 committed by Linus Groh
parent 2c87ff2218
commit 541637e15a
15 changed files with 861 additions and 68 deletions

View file

@ -235,21 +235,25 @@ Completion BlockStatement::execute(Interpreter& interpreter) const
auto& vm = interpreter.vm();
Environment* old_environment { nullptr };
ArmedScopeGuard restore_environment = [&] {
vm.running_execution_context().lexical_environment = old_environment;
};
// Optimization: We only need a new lexical environment if there are any lexical declarations. :^)
if (has_lexical_declarations()) {
old_environment = vm.running_execution_context().lexical_environment;
auto block_environment = new_declarative_environment(*old_environment);
block_declaration_instantiation(interpreter, block_environment);
vm.running_execution_context().lexical_environment = block_environment;
} else {
restore_environment.disarm();
}
if (!has_lexical_declarations())
return evaluate_statements(interpreter);
return evaluate_statements(interpreter);
old_environment = vm.running_execution_context().lexical_environment;
auto block_environment = new_declarative_environment(*old_environment);
block_declaration_instantiation(interpreter, block_environment);
vm.running_execution_context().lexical_environment = block_environment;
// 5. Let blockValue be the result of evaluating StatementList.
auto block_value = evaluate_statements(interpreter);
// 6. Set blockValue to DisposeResources(blockEnv, blockValue).
block_value = dispose_resources(vm, block_environment, block_value);
vm.running_execution_context().lexical_environment = old_environment;
return block_value;
}
Completion Program::execute(Interpreter& interpreter) const
@ -3015,6 +3019,48 @@ void VariableDeclaration::dump(int indent) const
declarator.dump(indent + 1);
}
// 6.2.1.2 Runtime Semantics: Evaluation, https://tc39.es/proposal-explicit-resource-management/#sec-let-and-const-declarations-runtime-semantics-evaluation
Completion UsingDeclaration::execute(Interpreter& interpreter) const
{
// 1. Let next be BindingEvaluation of BindingList with parameter sync-dispose.
InterpreterNodeScope node_scope { interpreter, *this };
auto& vm = interpreter.vm();
for (auto& declarator : m_declarations) {
VERIFY(declarator.target().has<NonnullRefPtr<Identifier>>());
VERIFY(declarator.init());
auto& id = declarator.target().get<NonnullRefPtr<Identifier>>();
// 2. ReturnIfAbrupt(next).
auto reference = TRY(id->to_reference(interpreter));
auto initializer_result = TRY(interpreter.vm().named_evaluation_if_anonymous_function(*declarator.init(), id->string()));
VERIFY(!initializer_result.is_empty());
TRY(reference.initialize_referenced_binding(vm, initializer_result, Environment::InitializeBindingHint::SyncDispose));
}
// 3. Return empty.
return normal_completion({});
}
ThrowCompletionOr<void> UsingDeclaration::for_each_bound_name(ThrowCompletionOrVoidCallback<DeprecatedFlyString const&>&& callback) const
{
for (auto const& entry : m_declarations) {
VERIFY(entry.target().has<NonnullRefPtr<Identifier>>());
TRY(callback(entry.target().get<NonnullRefPtr<Identifier>>()->string()));
}
return {};
}
void UsingDeclaration::dump(int indent) const
{
ASTNode::dump(indent);
print_indent(indent + 1);
for (auto& declarator : m_declarations)
declarator.dump(indent + 1);
}
void VariableDeclarator::dump(int indent) const
{
ASTNode::dump(indent);
@ -4154,11 +4200,13 @@ Completion SwitchStatement::execute_impl(Interpreter& interpreter) const
// 2. Let switchValue be ? GetValue(exprRef).
auto switch_value = TRY(m_discriminant->execute(interpreter)).release_value();
// 3. Let oldEnv be the running execution context's LexicalEnvironment.
auto* old_environment = interpreter.lexical_environment();
Completion result;
// Optimization: Avoid creating a lexical environment if there are no lexical declarations.
if (has_lexical_declarations()) {
// 3. Let oldEnv be the running execution context's LexicalEnvironment.
auto* old_environment = interpreter.lexical_environment();
// 4. Let blockEnv be NewDeclarativeEnvironment(oldEnv).
auto block_environment = new_declarative_environment(*old_environment);
@ -4167,15 +4215,23 @@ Completion SwitchStatement::execute_impl(Interpreter& interpreter) const
// 6. Set the running execution context's LexicalEnvironment to blockEnv.
vm.running_execution_context().lexical_environment = block_environment;
// 7. Let R be Completion(CaseBlockEvaluation of CaseBlock with argument switchValue).
result = case_block_evaluation(switch_value);
// 8. Let env be blockEnv's LexicalEnvironment.
// FIXME: blockEnv doesn't have a lexical env it is one?? Probably a spec issue
// 9. Set R to DisposeResources(env, R).
result = dispose_resources(vm, block_environment, result);
// 10. Set the running execution context's LexicalEnvironment to oldEnv.
vm.running_execution_context().lexical_environment = old_environment;
} else {
result = case_block_evaluation(switch_value);
}
// 7. Let R be Completion(CaseBlockEvaluation of CaseBlock with argument switchValue).
auto result = case_block_evaluation(switch_value);
// 8. Set the running execution context's LexicalEnvironment to oldEnv.
vm.running_execution_context().lexical_environment = old_environment;
// 9. Return R.
// 11. Return R.
return result;
}