diff --git a/Userland/Libraries/LibJS/AST.cpp b/Userland/Libraries/LibJS/AST.cpp index 4da5201576..18248ce5ec 100644 --- a/Userland/Libraries/LibJS/AST.cpp +++ b/Userland/Libraries/LibJS/AST.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2020-2021, Andreas Kling - * Copyright (c) 2020-2021, Linus Groh + * Copyright (c) 2020-2022, Linus Groh * Copyright (c) 2021, David Tuin * * SPDX-License-Identifier: BSD-2-Clause @@ -84,42 +84,41 @@ static ThrowCompletionOr get_function_name(GlobalObject& global_object, return value.to_string(global_object); } -Value ScopeNode::evaluate_statements(Interpreter& interpreter, GlobalObject& global_object) const +Completion ScopeNode::evaluate_statements(Interpreter& interpreter, GlobalObject& global_object) const { - // FIXME: This should use completions but for now we just use the vm to communicate things. auto& vm = interpreter.vm(); - Value last_value; - for (auto& node : children()) { - auto value = node.execute(interpreter, global_object); - if (!value.is_empty()) - last_value = value; - if (vm.should_unwind()) { + auto completion = normal_completion({}); + for (auto const& node : children()) { + completion = node.execute(interpreter, global_object).update_empty(completion.value()); + // FIXME: Use ReturnIfAbrupt once we get rid of the old unwinding mechanism. + // NOTE: There is *something* (iterators, I think) *somewhere* (no idea) incorrectly + // clearing the unwind state, causing us to get a throw completion here that thinks it + // doesn't need to unwind. Given that we're about to remove the unwinding mechanism + // altogether and it literally only affects 0.0001% of test262 tests (6 / 45156), this + // double check will do for now. + if (completion.is_abrupt() || vm.should_unwind()) break; - } } - return last_value; + return completion; } -Value FunctionBody::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion FunctionBody::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; // Note: Scoping should have already been set up by whoever is calling this FunctionBody. - auto function_result = evaluate_statements(interpreter, global_object); - - if (interpreter.exception()) - return {}; + auto function_result = TRY(evaluate_statements(interpreter, global_object)); if (interpreter.vm().unwind_until() != ScopeType::Function) function_result = js_undefined(); else interpreter.vm().stop_unwind(); - return function_result; + return normal_completion(move(function_result)); } // 14.2.2 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-block-runtime-semantics-evaluation -Value BlockStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion BlockStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; @@ -143,14 +142,10 @@ Value BlockStatement::execute(Interpreter& interpreter, GlobalObject& global_obj auto block_value = evaluate_statements(interpreter, global_object); if (!labels().is_empty() && vm.should_unwind_until(ScopeType::Breakable, labels())) vm.stop_unwind(); - - if (vm.exception()) - return {}; - return block_value; } -Value Program::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion Program::execute(Interpreter& interpreter, GlobalObject& global_object) const { // FIXME: This tries to be "ScriptEvaluation" and "evaluating scriptBody" at once. It shouldn't. // Clean this up and update perform_eval() / perform_shadow_realm_eval() @@ -160,12 +155,12 @@ Value Program::execute(Interpreter& interpreter, GlobalObject& global_object) co VERIFY(interpreter.lexical_environment() && interpreter.lexical_environment()->is_global_environment()); auto& global_env = static_cast(*interpreter.lexical_environment()); - TRY_OR_DISCARD(global_declaration_instantiation(interpreter, global_object, global_env)); + TRY(global_declaration_instantiation(interpreter, global_object, global_env)); return evaluate_statements(interpreter, global_object); } -Value FunctionDeclaration::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion FunctionDeclaration::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; @@ -177,12 +172,13 @@ Value FunctionDeclaration::execute(Interpreter& interpreter, GlobalObject& globa MUST(variable_environment->set_mutable_binding(global_object, name(), function_object, false)); } - return {}; + return normal_completion({}); } -Value FunctionExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion FunctionExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; + return instantiate_ordinary_function_expression(interpreter, global_object, name()); } @@ -214,85 +210,81 @@ Value FunctionExpression::instantiate_ordinary_function_expression(Interpreter& return closure; } -Value ExpressionStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion EmptyStatement::execute(Interpreter&, GlobalObject&) const +{ + return normal_completion({}); +} + +Completion ExpressionStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; return m_expression->execute(interpreter, global_object); } -CallExpression::ThisAndCallee CallExpression::compute_this_and_callee(Interpreter& interpreter, GlobalObject& global_object, Reference const& callee_reference) const +// TODO: This shouldn't exist. Refactor into EvaluateCall. +ThrowCompletionOr CallExpression::compute_this_and_callee(Interpreter& interpreter, GlobalObject& global_object, Reference const& callee_reference) const { if (callee_reference.is_property_reference()) { auto this_value = callee_reference.get_this_value(); - auto callee = TRY_OR_DISCARD(callee_reference.get_value(global_object)); + auto callee = TRY(callee_reference.get_value(global_object)); - return { this_value, callee }; + return ThisAndCallee { this_value, callee }; } // [[Call]] will handle that in non-strict mode the this value becomes the global object - return { + return ThisAndCallee { js_undefined(), callee_reference.is_unresolvable() - ? m_callee->execute(interpreter, global_object) - : TRY_OR_DISCARD(callee_reference.get_value(global_object)) + ? TRY(m_callee->execute(interpreter, global_object)).release_value() + : TRY(callee_reference.get_value(global_object)) }; } // 13.3.8.1 Runtime Semantics: ArgumentListEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-argumentlistevaluation -static void argument_list_evaluation(Interpreter& interpreter, GlobalObject& global_object, Vector const& arguments, MarkedValueList& list) +static ThrowCompletionOr argument_list_evaluation(Interpreter& interpreter, GlobalObject& global_object, Vector const& arguments, MarkedValueList& list) { - auto& vm = global_object.vm(); list.ensure_capacity(arguments.size()); for (auto& argument : arguments) { - auto value = argument.value->execute(interpreter, global_object); - if (vm.exception()) - return; + auto value = TRY(argument.value->execute(interpreter, global_object)).release_value(); if (argument.is_spread) { - auto result = get_iterator_values(global_object, value, [&](Value iterator_value) -> Optional { + auto result = TRY(get_iterator_values(global_object, value, [&](Value iterator_value) -> Optional { list.append(iterator_value); return {}; - }); - if (result.is_error()) - return; + })); } else { list.append(value); } } + return {}; } // 13.3.5.1 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-new-operator-runtime-semantics-evaluation // 13.3.5.1.1 EvaluateNew ( constructExpr, arguments ), https://tc39.es/ecma262/#sec-evaluatenew -Value NewExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion NewExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; auto& vm = interpreter.vm(); // 1. Let ref be the result of evaluating constructExpr. // 2. Let constructor be ? GetValue(ref). - auto constructor = m_callee->execute(interpreter, global_object); - if (vm.exception()) - return {}; + auto constructor = TRY(m_callee->execute(interpreter, global_object)).release_value(); // 3. If arguments is empty, let argList be a new empty List. // 4. Else, // a. Let argList be ? ArgumentListEvaluation of arguments. MarkedValueList arg_list(vm.heap()); - argument_list_evaluation(interpreter, global_object, m_arguments, arg_list); - if (interpreter.exception()) - return {}; + TRY(argument_list_evaluation(interpreter, global_object, m_arguments, arg_list)); // 5. If IsConstructor(constructor) is false, throw a TypeError exception. - if (!constructor.is_constructor()) { - throw_type_error_for_callee(interpreter, global_object, constructor, "constructor"sv); - return {}; - } + if (!constructor.is_constructor()) + return throw_type_error_for_callee(interpreter, global_object, constructor, "constructor"sv); // 6. Return ? Construct(constructor, argList). - return TRY_OR_DISCARD(construct(global_object, constructor.as_function(), move(arg_list))); + return Value { TRY(construct(global_object, constructor.as_function(), move(arg_list))) }; } -void CallExpression::throw_type_error_for_callee(Interpreter& interpreter, GlobalObject& global_object, Value callee_value, StringView call_type) const +Completion CallExpression::throw_type_error_for_callee(Interpreter& interpreter, GlobalObject& global_object, Value callee_value, StringView call_type) const { auto& vm = interpreter.vm(); if (is(*m_callee) || is(*m_callee)) { @@ -302,33 +294,27 @@ void CallExpression::throw_type_error_for_callee(Interpreter& interpreter, Globa } else { expression_string = static_cast(*m_callee).to_string_approximation(); } - vm.throw_exception(global_object, ErrorType::IsNotAEvaluatedFrom, callee_value.to_string_without_side_effects(), call_type, expression_string); + return vm.throw_completion(global_object, ErrorType::IsNotAEvaluatedFrom, callee_value.to_string_without_side_effects(), call_type, expression_string); } else { - vm.throw_exception(global_object, ErrorType::IsNotA, callee_value.to_string_without_side_effects(), call_type); + return vm.throw_completion(global_object, ErrorType::IsNotA, callee_value.to_string_without_side_effects(), call_type); } } -Value CallExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion CallExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; auto& vm = interpreter.vm(); - auto callee_reference = TRY_OR_DISCARD(m_callee->to_reference(interpreter, global_object)); + auto callee_reference = TRY(m_callee->to_reference(interpreter, global_object)); - auto [this_value, callee] = compute_this_and_callee(interpreter, global_object, callee_reference); - if (vm.exception()) - return {}; + auto [this_value, callee] = TRY(compute_this_and_callee(interpreter, global_object, callee_reference)); VERIFY(!callee.is_empty()); MarkedValueList arg_list(vm.heap()); - argument_list_evaluation(interpreter, global_object, m_arguments, arg_list); - if (interpreter.exception()) - return {}; + TRY(argument_list_evaluation(interpreter, global_object, m_arguments, arg_list)); - if (!callee.is_function()) { - throw_type_error_for_callee(interpreter, global_object, callee, "function"sv); - return {}; - } + if (!callee.is_function()) + return throw_type_error_for_callee(interpreter, global_object, callee, "function"sv); auto& function = callee.as_function(); @@ -338,15 +324,15 @@ Value CallExpression::execute(Interpreter& interpreter, GlobalObject& global_obj && callee_reference.name().as_string() == vm.names.eval.as_string()) { auto script_value = arg_list.size() == 0 ? js_undefined() : arg_list[0]; - return TRY_OR_DISCARD(perform_eval(script_value, global_object, vm.in_strict_mode() ? CallerMode::Strict : CallerMode::NonStrict, EvalMode::Direct)); + return perform_eval(script_value, global_object, vm.in_strict_mode() ? CallerMode::Strict : CallerMode::NonStrict, EvalMode::Direct); } - return TRY_OR_DISCARD(vm.call(function, this_value, move(arg_list))); + return vm.call(function, this_value, move(arg_list)); } // 13.3.7.1 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation // SuperCall : super Arguments -Value SuperCall::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion SuperCall::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; auto& vm = interpreter.vm(); @@ -363,198 +349,177 @@ Value SuperCall::execute(Interpreter& interpreter, GlobalObject& global_object) // 4. Let argList be ? ArgumentListEvaluation of Arguments. MarkedValueList arg_list(vm.heap()); - argument_list_evaluation(interpreter, global_object, m_arguments, arg_list); - if (interpreter.exception()) - return {}; + TRY(argument_list_evaluation(interpreter, global_object, m_arguments, arg_list)); // 5. If IsConstructor(func) is false, throw a TypeError exception. - if (!func || !Value(func).is_constructor()) { - vm.throw_exception(global_object, ErrorType::NotAConstructor, "Super constructor"); - return {}; - } + if (!func || !Value(func).is_constructor()) + return vm.throw_completion(global_object, ErrorType::NotAConstructor, "Super constructor"); // 6. Let result be ? Construct(func, argList, newTarget). - auto* result = TRY_OR_DISCARD(construct(global_object, static_cast(*func), move(arg_list), &new_target.as_function())); + auto* result = TRY(construct(global_object, static_cast(*func), move(arg_list), &new_target.as_function())); // 7. Let thisER be GetThisEnvironment(). auto& this_er = verify_cast(get_this_environment(interpreter.vm())); // 8. Perform ? thisER.BindThisValue(result). - TRY_OR_DISCARD(this_er.bind_this_value(global_object, result)); + TRY(this_er.bind_this_value(global_object, result)); // 9. Let F be thisER.[[FunctionObject]]. // 10. Assert: F is an ECMAScript function object. (NOTE: This is implied by the strong C++ type.) [[maybe_unused]] auto& f = this_er.function_object(); // 11. Perform ? InitializeInstanceElements(result, F). - TRY_OR_DISCARD(vm.initialize_instance_elements(*result, f)); + TRY(vm.initialize_instance_elements(*result, f)); // 12. Return result. - return result; + return Value { result }; } -Value YieldExpression::execute(Interpreter&, GlobalObject&) const +Completion YieldExpression::execute(Interpreter&, GlobalObject&) const { // This should be transformed to a return. VERIFY_NOT_REACHED(); } // 15.8.5 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-async-function-definitions-runtime-semantics-evaluation -Value AwaitExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion AwaitExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; // 1. Let exprRef be the result of evaluating UnaryExpression. // 2. Let value be ? GetValue(exprRef). - auto value = m_argument->execute(interpreter, global_object); - if (interpreter.exception()) - return {}; + auto value = TRY(m_argument->execute(interpreter, global_object)).release_value(); // 3. Return ? Await(value). - return TRY_OR_DISCARD(await(global_object, value)); + return await(global_object, value); } -Value ReturnStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion ReturnStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; - auto value = argument() ? argument()->execute(interpreter, global_object) : js_undefined(); - if (interpreter.exception()) - return {}; + + // TODO: Return 'return' completion + auto value = argument() ? TRY(argument()->execute(interpreter, global_object)).release_value() : js_undefined(); interpreter.vm().unwind(ScopeType::Function); return value; } // 14.6.2 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-if-statement-runtime-semantics-evaluation -Value IfStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion IfStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; // IfStatement : if ( Expression ) Statement else Statement // 1. Let exprRef be the result of evaluating Expression. // 2. Let exprValue be ! ToBoolean(? GetValue(exprRef)). - auto predicate_result = m_predicate->execute(interpreter, global_object); - if (interpreter.exception()) - return {}; + auto predicate_result = TRY(m_predicate->execute(interpreter, global_object)).release_value(); // 3. If exprValue is true, then if (predicate_result.to_boolean()) { // a. Let stmtCompletion be the result of evaluating the second Statement. // 5. Return Completion(UpdateEmpty(stmtCompletion, undefined)). - return m_consequent->execute(interpreter, global_object).value_or(js_undefined()); + return m_consequent->execute(interpreter, global_object).update_empty(js_undefined()); } // 4. Else, if (m_alternate) { // a. Let stmtCompletion be the result of evaluating the second Statement. // 5. Return Completion(UpdateEmpty(stmtCompletion, undefined)). - return m_alternate->execute(interpreter, global_object).value_or(js_undefined()); + return m_alternate->execute(interpreter, global_object).update_empty(js_undefined()); } // IfStatement : if ( Expression ) Statement // 3. If exprValue is false, then // a. Return NormalCompletion(undefined). - return js_undefined(); + return normal_completion(js_undefined()); } // 14.11.2 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-with-statement-runtime-semantics-evaluation // WithStatement : with ( Expression ) Statement -Value WithStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion WithStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; // 1. Let value be the result of evaluating Expression. - auto value = m_object->execute(interpreter, global_object); - if (interpreter.exception()) - return {}; + auto value = TRY(m_object->execute(interpreter, global_object)).release_value(); // 2. Let obj be ? ToObject(? GetValue(value)). - auto* object = TRY_OR_DISCARD(value.to_object(global_object)); + auto* object = TRY(value.to_object(global_object)); // 3. Let oldEnv be the running execution context's LexicalEnvironment. auto* old_environment = interpreter.vm().running_execution_context().lexical_environment; // 4. Let newEnv be NewObjectEnvironment(obj, true, oldEnv). auto* new_environment = new_object_environment(*object, true, old_environment); - if (interpreter.exception()) - return {}; // 5. Set the running execution context's LexicalEnvironment to newEnv. interpreter.vm().running_execution_context().lexical_environment = new_environment; // 6. Let C be the result of evaluating Statement. - auto result = m_body->execute(interpreter, global_object).value_or(js_undefined()); + auto result = m_body->execute(interpreter, global_object); // 7. Set the running execution context's LexicalEnvironment to oldEnv. interpreter.vm().running_execution_context().lexical_environment = old_environment; - if (interpreter.exception()) - return {}; - // 8. Return Completion(UpdateEmpty(C, undefined)). - return result; + return result.update_empty(js_undefined()); } -Value WhileStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion WhileStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; auto last_value = js_undefined(); for (;;) { - auto test_result = m_test->execute(interpreter, global_object); - if (interpreter.exception()) - return {}; + auto test_result = TRY(m_test->execute(interpreter, global_object)).release_value(); if (!test_result.to_boolean()) - break; - last_value = m_body->execute(interpreter, global_object).value_or(last_value); - if (interpreter.exception()) - return {}; + return normal_completion(last_value); + auto body_result = m_body->execute(interpreter, global_object); if (interpreter.vm().should_unwind()) { if (interpreter.vm().should_unwind_until(ScopeType::Continuable, m_labels)) { interpreter.vm().stop_unwind(); } else if (interpreter.vm().should_unwind_until(ScopeType::Breakable, m_labels)) { interpreter.vm().stop_unwind(); - break; + return body_result.update_empty(last_value); } else { - return last_value; + return body_result.update_empty(last_value); } } + if (body_result.value().has_value()) + last_value = *body_result.value(); } - return last_value; + VERIFY_NOT_REACHED(); } -Value DoWhileStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion DoWhileStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; auto last_value = js_undefined(); for (;;) { - if (interpreter.exception()) - return {}; - last_value = m_body->execute(interpreter, global_object).value_or(last_value); - if (interpreter.exception()) - return {}; + auto body_result = m_body->execute(interpreter, global_object); if (interpreter.vm().should_unwind()) { if (interpreter.vm().should_unwind_until(ScopeType::Continuable, m_labels)) { interpreter.vm().stop_unwind(); } else if (interpreter.vm().should_unwind_until(ScopeType::Breakable, m_labels)) { interpreter.vm().stop_unwind(); - break; + return body_result.update_empty(last_value); } else { - return last_value; + return body_result.update_empty(last_value); } } - auto test_result = m_test->execute(interpreter, global_object); - if (interpreter.exception()) - return {}; + if (body_result.value().has_value()) + last_value = *body_result.value(); + auto test_result = TRY(m_test->execute(interpreter, global_object)).release_value(); if (!test_result.to_boolean()) - break; + return normal_completion(last_value); } - return last_value; + VERIFY_NOT_REACHED(); } -Value ForStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion ForStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; @@ -577,19 +542,14 @@ Value ForStatement::execute(Interpreter& interpreter, GlobalObject& global_objec MUST(loop_environment->create_mutable_binding(global_object, name, false)); let_declarations.append(name); } - return IterationDecision::Continue; }); interpreter.vm().running_execution_context().lexical_environment = loop_environment; } - m_init->execute(interpreter, global_object); - if (interpreter.exception()) - return {}; + (void)TRY(m_init->execute(interpreter, global_object)); } - auto last_value = js_undefined(); - // 14.7.4.4 CreatePerIterationEnvironment ( perIterationBindings ), https://tc39.es/ecma262/#sec-createperiterationenvironment auto create_per_iteration_environment = [&]() -> ThrowCompletionOr { if (let_declarations.is_empty()) @@ -610,47 +570,39 @@ Value ForStatement::execute(Interpreter& interpreter, GlobalObject& global_objec return {}; }; - TRY_OR_DISCARD(create_per_iteration_environment()); + auto last_value = js_undefined(); - auto test_empty_or_true = [&] { - if (!m_test) - return true; - - auto test_result = m_test->execute(interpreter, global_object); - if (interpreter.exception()) - return false; - return test_result.to_boolean(); - }; + TRY(create_per_iteration_environment()); while (true) { - if (!test_empty_or_true()) - break; + if (m_test) { + auto test_value = TRY(m_test->execute(interpreter, global_object)).release_value(); + if (!test_value.to_boolean()) + return normal_completion(last_value); + } - last_value = m_body->execute(interpreter, global_object).value_or(last_value); - if (interpreter.exception()) - return {}; + auto result = m_body->execute(interpreter, global_object); if (interpreter.vm().should_unwind()) { if (interpreter.vm().should_unwind_until(ScopeType::Continuable, m_labels)) { interpreter.vm().stop_unwind(); } else if (interpreter.vm().should_unwind_until(ScopeType::Breakable, m_labels)) { interpreter.vm().stop_unwind(); - break; + return result.update_empty(last_value); } else { - return last_value; + return result.update_empty(last_value); } } - TRY_OR_DISCARD(create_per_iteration_environment()); + if (result.value().has_value()) + last_value = *result.value(); + TRY(create_per_iteration_environment()); if (m_update) { - m_update->execute(interpreter, global_object); - if (interpreter.exception()) - return {}; + (void)TRY(m_update->execute(interpreter, global_object)); } } - if (interpreter.exception()) - return {}; - return last_value; + + VERIFY_NOT_REACHED(); } struct ForInOfHeadState { @@ -775,9 +727,6 @@ static ThrowCompletionOr for_in_of_head_execute(Interpreter& i VERIFY(variable.target().has>()); auto& binding_id = variable.target().get>()->string(); auto reference = TRY(interpreter.vm().resolve_binding(binding_id)); - if (auto* exception = interpreter.exception()) - return throw_completion(exception->value()); - auto result = TRY(interpreter.vm().named_evaluation_if_anonymous_function(global_object, *variable.init(), binding_id)); TRY(reference.put_value(global_object, result)); } @@ -795,7 +744,7 @@ static ThrowCompletionOr for_in_of_head_execute(Interpreter& i // 3. Let exprRef be the result of evaluating expr. // 5. Let exprValue be ? GetValue(exprRef). - state.rhs_value = rhs.execute(interpreter, global_object); + state.rhs_value = TRY(rhs.execute(interpreter, global_object)).release_value(); // Note that since a reference stores its environment it doesn't matter we only reset // this after step 5. (Also we have no way of separating these steps at this point) @@ -803,12 +752,9 @@ static ThrowCompletionOr for_in_of_head_execute(Interpreter& i } else { // 3. Let exprRef be the result of evaluating expr. // 5. Let exprValue be ? GetValue(exprRef). - state.rhs_value = rhs.execute(interpreter, global_object); + state.rhs_value = TRY(rhs.execute(interpreter, global_object)).release_value(); } - if (auto* exception = interpreter.exception()) - return throw_completion(exception->value()); - return state; } @@ -821,23 +767,23 @@ static ThrowCompletionOr for_in_of_head_execute(Interpreter& i // We can skip step 1, 2 and 4 here (on top of already skipping step 6 and 7). // 3. Let exprRef be the result of evaluating expr. // 5. Let exprValue be ? GetValue(exprRef). - state.rhs_value = rhs.execute(interpreter, global_object); - if (auto* exception = interpreter.exception()) - return throw_completion(exception->value()); + state.rhs_value = TRY(rhs.execute(interpreter, global_object)).release_value(); return state; } -Value ForInStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion ForInStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; - auto for_in_head_state = TRY_OR_DISCARD(for_in_of_head_execute(interpreter, global_object, m_lhs, *m_rhs)); + auto for_in_head_state = TRY(for_in_of_head_execute(interpreter, global_object, m_lhs, *m_rhs)); auto rhs_result = for_in_head_state.rhs_value; // 14.7.5.6 ForIn/OfHeadEvaluation ( uninitializedBoundNames, expr, iterationKind ), https://tc39.es/ecma262/#sec-runtime-semantics-forinofheadevaluation - if (rhs_result.is_nullish()) + if (rhs_result.is_nullish()) { + // TODO: Return 'break' completion return js_undefined(); + } auto* object = MUST(rhs_result.to_object(global_object)); @@ -848,38 +794,40 @@ Value ForInStatement::execute(Interpreter& interpreter, GlobalObject& global_obj }); auto last_value = js_undefined(); + while (object) { - auto property_names = TRY_OR_DISCARD(object->enumerable_own_property_names(Object::PropertyKind::Key)); + auto property_names = TRY(object->enumerable_own_property_names(Object::PropertyKind::Key)); for (auto& value : property_names) { - TRY_OR_DISCARD(for_in_head_state.execute_head(interpreter, global_object, value)); - last_value = m_body->execute(interpreter, global_object).value_or(last_value); + TRY(for_in_head_state.execute_head(interpreter, global_object, value)); + auto result = m_body->execute(interpreter, global_object); interpreter.vm().running_execution_context().lexical_environment = old_environment; - if (interpreter.exception()) - return {}; + if (auto* exception = interpreter.exception()) + return throw_completion(exception->value()); if (interpreter.vm().should_unwind()) { if (interpreter.vm().should_unwind_until(ScopeType::Continuable, m_labels)) { interpreter.vm().stop_unwind(); } else if (interpreter.vm().should_unwind_until(ScopeType::Breakable, m_labels)) { interpreter.vm().stop_unwind(); - break; + return result.update_empty(last_value); } else { - return last_value; + return result.update_empty(last_value); } } + if (result.value().has_value()) + last_value = *result.value(); } - object = TRY_OR_DISCARD(object->internal_get_prototype_of()); + object = TRY(object->internal_get_prototype_of()); } return last_value; } -Value ForOfStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion ForOfStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; - auto for_of_head_state = TRY_OR_DISCARD(for_in_of_head_execute(interpreter, global_object, m_lhs, m_rhs)); + auto for_of_head_state = TRY(for_in_of_head_execute(interpreter, global_object, m_lhs, m_rhs)); auto rhs_result = for_of_head_state.rhs_value; - auto last_value = js_undefined(); // 14.7.5.7 ForIn/OfBodyEvaluation ( lhs, stmt, iteratorRecord, iterationKind, lhsKind, labelSet [ , iteratorKind ] ), https://tc39.es/ecma262/#sec-runtime-semantics-forin-div-ofbodyevaluation-lhs-stmt-iterator-lhskind-labelset // We use get_iterator_values which behaves like ForIn/OfBodyEvaluation with iteratorKind iterate. @@ -888,10 +836,17 @@ Value ForOfStatement::execute(Interpreter& interpreter, GlobalObject& global_obj interpreter.vm().running_execution_context().lexical_environment = old_environment; }); - (void)TRY_OR_DISCARD(get_iterator_values(global_object, rhs_result, [&](Value value) -> Optional { + auto last_value = js_undefined(); + + (void)TRY(get_iterator_values(global_object, rhs_result, [&](Value value) -> Optional { TRY(for_of_head_state.execute_head(interpreter, global_object, value)); - last_value = m_body->execute(interpreter, global_object).value_or(last_value); + auto result = m_body->execute(interpreter, global_object); interpreter.vm().running_execution_context().lexical_environment = old_environment; + // NOTE: We need to do this out of order as we can't directly return from here as we're + // supposed to, since this is the get_iterator_values() callback. Instead, we have to rely + // on updating the outer last_value. + if (result.value().has_value()) + last_value = *result.value(); if (auto* exception = interpreter.exception()) return throw_completion(exception->value()); if (interpreter.vm().should_unwind()) { @@ -910,19 +865,19 @@ Value ForOfStatement::execute(Interpreter& interpreter, GlobalObject& global_obj return last_value; } -Value ForAwaitOfStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion ForAwaitOfStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; // 14.7.5.6 ForIn/OfHeadEvaluation ( uninitializedBoundNames, expr, iterationKind ), https://tc39.es/ecma262/#sec-runtime-semantics-forinofheadevaluation // Note: Performs only steps 1 through 5. - auto for_of_head_state = TRY_OR_DISCARD(for_in_of_head_execute(interpreter, global_object, m_lhs, m_rhs)); + auto for_of_head_state = TRY(for_in_of_head_execute(interpreter, global_object, m_lhs, m_rhs)); auto rhs_result = for_of_head_state.rhs_value; // NOTE: Perform step 7 from ForIn/OfHeadEvaluation. And since this is always async we only have to do step 7.d. // d. Return ? GetIterator(exprValue, iteratorHint). - auto* iterator = TRY_OR_DISCARD(get_iterator(global_object, rhs_result, IteratorHint::Async)); + auto* iterator = TRY(get_iterator(global_object, rhs_result, IteratorHint::Async)); VERIFY(iterator); auto& vm = interpreter.vm(); @@ -943,34 +898,30 @@ Value ForAwaitOfStatement::execute(Interpreter& interpreter, GlobalObject& globa // 6. Repeat, while (true) { // NOTE: Since we don't have iterator records yet we have to extract the function first. - auto next_method = TRY_OR_DISCARD(iterator->get(vm.names.next)); - if (!next_method.is_function()) { - vm.throw_exception(global_object, ErrorType::IterableNextNotAFunction); - return {}; - } + auto next_method = TRY(iterator->get(vm.names.next)); + if (!next_method.is_function()) + return vm.throw_completion(global_object, ErrorType::IterableNextNotAFunction); // a. Let nextResult be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]). - auto next_result = TRY_OR_DISCARD(call(global_object, next_method, iterator)); + auto next_result = TRY(call(global_object, next_method, iterator)); // b. If iteratorKind is async, set nextResult to ? Await(nextResult). - next_result = TRY_OR_DISCARD(await(global_object, next_result)); + next_result = TRY(await(global_object, next_result)); // c. If Type(nextResult) is not Object, throw a TypeError exception. - if (!next_result.is_object()) { - vm.throw_exception(global_object, ErrorType::IterableNextBadReturn); - return {}; - } + if (!next_result.is_object()) + return vm.throw_completion(global_object, ErrorType::IterableNextBadReturn); // d. Let done be ? IteratorComplete(nextResult). - auto done = TRY_OR_DISCARD(iterator_complete(global_object, next_result.as_object())); + auto done = TRY(iterator_complete(global_object, next_result.as_object())); // e. If done is true, return NormalCompletion(V). if (done) return last_value; // f. Let nextValue be ? IteratorValue(nextResult). - auto next_value = TRY_OR_DISCARD(iterator_value(global_object, next_result.as_object())); + auto next_value = TRY(iterator_value(global_object, next_result.as_object())); // NOTE: This performs steps g. through to k. - TRY_OR_DISCARD(for_of_head_state.execute_head(interpreter, global_object, next_value)); + TRY(for_of_head_state.execute_head(interpreter, global_object, next_value)); // l. Let result be the result of evaluating stmt. auto result = m_body->execute(interpreter, global_object); @@ -978,13 +929,11 @@ Value ForAwaitOfStatement::execute(Interpreter& interpreter, GlobalObject& globa // m. Set the running execution context's LexicalEnvironment to oldEnv. interpreter.vm().running_execution_context().lexical_environment = old_environment; - // NOTE: Since execute does not return a completion we have to have a number of checks here. + // NOTE: Until we use the full range of completion types, we have to have a number of checks here. // n. If LoopContinues(result, labelSet) is false, then if (auto* exception = vm.exception()) { - // FIXME: We should return the result of AsyncIteratorClose but cannot return completions yet. // 3. If iteratorKind is async, return ? AsyncIteratorClose(iteratorRecord, status). - TRY_OR_DISCARD(async_iterator_close(*iterator, throw_completion(exception->value()))); - return {}; + return async_iterator_close(*iterator, throw_completion(exception->value())); } if (interpreter.vm().should_unwind()) { @@ -994,29 +943,27 @@ Value ForAwaitOfStatement::execute(Interpreter& interpreter, GlobalObject& globa } else if (interpreter.vm().should_unwind_until(ScopeType::Breakable, m_labels)) { interpreter.vm().stop_unwind(); // 2. Set status to UpdateEmpty(result, V). - if (!result.is_empty()) - last_value = result; + auto status = result.update_empty(last_value); + // 3. If iteratorKind is async, return ? AsyncIteratorClose(iteratorRecord, status). - TRY_OR_DISCARD(async_iterator_close(*iterator, normal_completion(last_value))); - return last_value; + return async_iterator_close(*iterator, move(status)); } else { // 2. Set status to UpdateEmpty(result, V). - if (!result.is_empty()) - last_value = result; + auto status = result.update_empty(last_value); + // 3. If iteratorKind is async, return ? AsyncIteratorClose(iteratorRecord, status). - TRY_OR_DISCARD(async_iterator_close(*iterator, normal_completion(last_value))); - return last_value; + return async_iterator_close(*iterator, move(status)); } } // o. If result.[[Value]] is not empty, set V to result.[[Value]]. - if (!result.is_empty()) - last_value = result; + if (result.value().has_value()) + last_value = *result.value(); } VERIFY_NOT_REACHED(); } -Value BinaryExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion BinaryExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; @@ -1025,108 +972,86 @@ Value BinaryExpression::execute(Interpreter& interpreter, GlobalObject& global_o if (m_op == BinaryOp::In && is(*m_lhs)) { auto& private_identifier = static_cast(*m_lhs).string(); - auto rhs_result = m_rhs->execute(interpreter, global_object); - if (interpreter.exception()) - return {}; - if (!rhs_result.is_object()) { - interpreter.vm().throw_exception(global_object, ErrorType::InOperatorWithObject); - return {}; - } + auto rhs_result = TRY(m_rhs->execute(interpreter, global_object)).release_value(); + if (!rhs_result.is_object()) + return interpreter.vm().throw_completion(global_object, ErrorType::InOperatorWithObject); auto* private_environment = interpreter.vm().running_execution_context().private_environment; VERIFY(private_environment); auto private_name = private_environment->resolve_private_identifier(private_identifier); return Value(rhs_result.as_object().private_element_find(private_name) != nullptr); } - auto lhs_result = m_lhs->execute(interpreter, global_object); - if (interpreter.exception()) - return {}; - auto rhs_result = m_rhs->execute(interpreter, global_object); - if (interpreter.exception()) - return {}; + auto lhs_result = TRY(m_lhs->execute(interpreter, global_object)).release_value(); + auto rhs_result = TRY(m_rhs->execute(interpreter, global_object)).release_value(); switch (m_op) { case BinaryOp::Addition: - return TRY_OR_DISCARD(add(global_object, lhs_result, rhs_result)); + return TRY(add(global_object, lhs_result, rhs_result)); case BinaryOp::Subtraction: - return TRY_OR_DISCARD(sub(global_object, lhs_result, rhs_result)); + return TRY(sub(global_object, lhs_result, rhs_result)); case BinaryOp::Multiplication: - return TRY_OR_DISCARD(mul(global_object, lhs_result, rhs_result)); + return TRY(mul(global_object, lhs_result, rhs_result)); case BinaryOp::Division: - return TRY_OR_DISCARD(div(global_object, lhs_result, rhs_result)); + return TRY(div(global_object, lhs_result, rhs_result)); case BinaryOp::Modulo: - return TRY_OR_DISCARD(mod(global_object, lhs_result, rhs_result)); + return TRY(mod(global_object, lhs_result, rhs_result)); case BinaryOp::Exponentiation: - return TRY_OR_DISCARD(exp(global_object, lhs_result, rhs_result)); + return TRY(exp(global_object, lhs_result, rhs_result)); case BinaryOp::StrictlyEquals: return Value(is_strictly_equal(lhs_result, rhs_result)); case BinaryOp::StrictlyInequals: return Value(!is_strictly_equal(lhs_result, rhs_result)); case BinaryOp::LooselyEquals: - return Value(TRY_OR_DISCARD(is_loosely_equal(global_object, lhs_result, rhs_result))); + return Value(TRY(is_loosely_equal(global_object, lhs_result, rhs_result))); case BinaryOp::LooselyInequals: - return Value(!TRY_OR_DISCARD(is_loosely_equal(global_object, lhs_result, rhs_result))); + return Value(!TRY(is_loosely_equal(global_object, lhs_result, rhs_result))); case BinaryOp::GreaterThan: - return TRY_OR_DISCARD(greater_than(global_object, lhs_result, rhs_result)); + return TRY(greater_than(global_object, lhs_result, rhs_result)); case BinaryOp::GreaterThanEquals: - return TRY_OR_DISCARD(greater_than_equals(global_object, lhs_result, rhs_result)); + return TRY(greater_than_equals(global_object, lhs_result, rhs_result)); case BinaryOp::LessThan: - return TRY_OR_DISCARD(less_than(global_object, lhs_result, rhs_result)); + return TRY(less_than(global_object, lhs_result, rhs_result)); case BinaryOp::LessThanEquals: - return TRY_OR_DISCARD(less_than_equals(global_object, lhs_result, rhs_result)); + return TRY(less_than_equals(global_object, lhs_result, rhs_result)); case BinaryOp::BitwiseAnd: - return TRY_OR_DISCARD(bitwise_and(global_object, lhs_result, rhs_result)); + return TRY(bitwise_and(global_object, lhs_result, rhs_result)); case BinaryOp::BitwiseOr: - return TRY_OR_DISCARD(bitwise_or(global_object, lhs_result, rhs_result)); + return TRY(bitwise_or(global_object, lhs_result, rhs_result)); case BinaryOp::BitwiseXor: - return TRY_OR_DISCARD(bitwise_xor(global_object, lhs_result, rhs_result)); + return TRY(bitwise_xor(global_object, lhs_result, rhs_result)); case BinaryOp::LeftShift: - return TRY_OR_DISCARD(left_shift(global_object, lhs_result, rhs_result)); + return TRY(left_shift(global_object, lhs_result, rhs_result)); case BinaryOp::RightShift: - return TRY_OR_DISCARD(right_shift(global_object, lhs_result, rhs_result)); + return TRY(right_shift(global_object, lhs_result, rhs_result)); case BinaryOp::UnsignedRightShift: - return TRY_OR_DISCARD(unsigned_right_shift(global_object, lhs_result, rhs_result)); + return TRY(unsigned_right_shift(global_object, lhs_result, rhs_result)); case BinaryOp::In: - return TRY_OR_DISCARD(in(global_object, lhs_result, rhs_result)); + return TRY(in(global_object, lhs_result, rhs_result)); case BinaryOp::InstanceOf: - return TRY_OR_DISCARD(instance_of(global_object, lhs_result, rhs_result)); + return TRY(instance_of(global_object, lhs_result, rhs_result)); } VERIFY_NOT_REACHED(); } -Value LogicalExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion LogicalExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; - auto lhs_result = m_lhs->execute(interpreter, global_object); - if (interpreter.exception()) - return {}; + auto lhs_result = TRY(m_lhs->execute(interpreter, global_object)).release_value(); switch (m_op) { case LogicalOp::And: - if (lhs_result.to_boolean()) { - auto rhs_result = m_rhs->execute(interpreter, global_object); - if (interpreter.exception()) - return {}; - return rhs_result; - } - return lhs_result; - case LogicalOp::Or: { + if (!lhs_result.to_boolean()) + return lhs_result; + return m_rhs->execute(interpreter, global_object); + case LogicalOp::Or: if (lhs_result.to_boolean()) return lhs_result; - auto rhs_result = m_rhs->execute(interpreter, global_object); - if (interpreter.exception()) - return {}; - return rhs_result; - } + return m_rhs->execute(interpreter, global_object); case LogicalOp::NullishCoalescing: - if (lhs_result.is_nullish()) { - auto rhs_result = m_rhs->execute(interpreter, global_object); - if (interpreter.exception()) - return {}; - return rhs_result; - } + if (lhs_result.is_nullish()) + return m_rhs->execute(interpreter, global_object); return lhs_result; } @@ -1177,9 +1102,8 @@ ThrowCompletionOr MemberExpression::to_reference(Interpreter& interpr // 3. Let propertyNameReference be the result of evaluating Expression. // 4. Let propertyNameValue be ? GetValue(propertyNameReference). - auto property_name_value = m_property->execute(interpreter, global_object); - if (auto* exception = interpreter.exception()) - return throw_completion(exception->value()); + auto property_name_value = TRY(m_property->execute(interpreter, global_object)).release_value(); + // 5. Let propertyKey be ? ToPropertyKey(propertyNameValue). property_key = TRY(property_name_value.to_property_key(global_object)); } else { @@ -1204,10 +1128,8 @@ ThrowCompletionOr MemberExpression::to_reference(Interpreter& interpr if (base_reference.is_valid_reference()) base_value = TRY(base_reference.get_value(global_object)); else - base_value = m_object->execute(interpreter, global_object); + base_value = TRY(m_object->execute(interpreter, global_object)).release_value(); - if (auto* exception = interpreter.exception()) - return throw_completion(exception->value()); VERIFY(!base_value.is_empty()); // From here on equivalent to @@ -1215,13 +1137,11 @@ ThrowCompletionOr MemberExpression::to_reference(Interpreter& interpr PropertyKey property_name; if (is_computed()) { // Weird order which I can't quite find from the specs. - auto value = m_property->execute(interpreter, global_object); - if (auto* exception = interpreter.exception()) - return throw_completion(exception->value()); + auto value = TRY(m_property->execute(interpreter, global_object)).release_value(); + VERIFY(!value.is_empty()); TRY(require_object_coercible(global_object, base_value)); - VERIFY(!value.is_empty()); property_name = PropertyKey::from_value(global_object, value); if (auto* exception = interpreter.exception()) return throw_completion(exception->value()); @@ -1239,42 +1159,40 @@ ThrowCompletionOr MemberExpression::to_reference(Interpreter& interpr return Reference { base_value, move(property_name), {}, strict }; } -Value UnaryExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion UnaryExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; auto& vm = interpreter.vm(); if (m_op == UnaryOp::Delete) { - auto reference = TRY_OR_DISCARD(m_lhs->to_reference(interpreter, global_object)); - return Value(TRY_OR_DISCARD(reference.delete_(global_object))); + auto reference = TRY(m_lhs->to_reference(interpreter, global_object)); + return Value(TRY(reference.delete_(global_object))); } Value lhs_result; if (m_op == UnaryOp::Typeof && is(*m_lhs)) { - auto reference = TRY_OR_DISCARD(m_lhs->to_reference(interpreter, global_object)); + auto reference = TRY(m_lhs->to_reference(interpreter, global_object)); if (reference.is_unresolvable()) lhs_result = js_undefined(); else - lhs_result = TRY_OR_DISCARD(reference.get_value(global_object)); + lhs_result = TRY(reference.get_value(global_object)); VERIFY(!lhs_result.is_empty()); } else { - lhs_result = m_lhs->execute(interpreter, global_object); - if (interpreter.exception()) - return {}; + lhs_result = TRY(m_lhs->execute(interpreter, global_object)).release_value(); } switch (m_op) { case UnaryOp::BitwiseNot: - return TRY_OR_DISCARD(bitwise_not(global_object, lhs_result)); + return TRY(bitwise_not(global_object, lhs_result)); case UnaryOp::Not: return Value(!lhs_result.to_boolean()); case UnaryOp::Plus: - return TRY_OR_DISCARD(unary_plus(global_object, lhs_result)); + return TRY(unary_plus(global_object, lhs_result)); case UnaryOp::Minus: - return TRY_OR_DISCARD(unary_minus(global_object, lhs_result)); + return TRY(unary_minus(global_object, lhs_result)); case UnaryOp::Typeof: - return js_string(vm, lhs_result.typeof()); + return Value { js_string(vm, lhs_result.typeof()) }; case UnaryOp::Void: return js_undefined(); case UnaryOp::Delete: @@ -1284,13 +1202,13 @@ Value UnaryExpression::execute(Interpreter& interpreter, GlobalObject& global_ob VERIFY_NOT_REACHED(); } -Value SuperExpression::execute(Interpreter&, GlobalObject&) const +Completion SuperExpression::execute(Interpreter&, GlobalObject&) const { // The semantics for SuperExpression are handled in CallExpression and SuperCall. VERIFY_NOT_REACHED(); } -Value ClassElement::execute(Interpreter&, GlobalObject&) const +Completion ClassElement::execute(Interpreter&, GlobalObject&) const { // Note: The semantics of class element are handled in class_element_evaluation VERIFY_NOT_REACHED(); @@ -1305,9 +1223,7 @@ static ThrowCompletionOr class_key_to_property_n return ClassElement::ClassElementName { private_environment->resolve_private_identifier(private_identifier.string()) }; } - auto prop_key = key.execute(interpreter, global_object); - if (auto* exception = interpreter.exception()) - return throw_completion(exception->value()); + auto prop_key = TRY(key.execute(interpreter, global_object)).release_value(); if (prop_key.is_object()) prop_key = TRY(prop_key.to_primitive(global_object, Value::PreferredType::String)); @@ -1323,9 +1239,7 @@ ThrowCompletionOr ClassMethod::class_element_evaluatio { auto property_key = TRY(class_key_to_property_name(interpreter, global_object, *m_key)); - auto method_value = m_function->execute(interpreter, global_object); - if (auto* exception = interpreter.exception()) - return throw_completion(exception->value()); + auto method_value = TRY(m_function->execute(interpreter, global_object)).release_value(); auto& method_function = static_cast(method_value.as_function()); method_function.make_method(target); @@ -1398,11 +1312,11 @@ public: { } - Value execute(Interpreter& interpreter, GlobalObject& global_object) const override + Completion execute(Interpreter& interpreter, GlobalObject& global_object) const override { VERIFY(interpreter.vm().argument_count() == 0); VERIFY(!m_class_field_identifier_name.is_empty()); - return TRY_OR_DISCARD(interpreter.vm().named_evaluation_if_anonymous_function(global_object, m_expression, m_class_field_identifier_name)); + return TRY(interpreter.vm().named_evaluation_if_anonymous_function(global_object, m_expression, m_class_field_identifier_name)); } void dump(int) const override @@ -1475,25 +1389,21 @@ ThrowCompletionOr StaticInitializer::class_element_eva return ClassValue { normal_completion(body_function) }; } -Value ClassExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion ClassExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; // FIXME: Set value.[[SourceText]] to the source text matched by ClassExpression. - return TRY_OR_DISCARD(class_definition_evaluation(interpreter, global_object, m_name, m_name.is_null() ? "" : m_name)); + return TRY(class_definition_evaluation(interpreter, global_object, m_name, m_name.is_null() ? "" : m_name)); } -Value ClassDeclaration::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion ClassDeclaration::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; - auto name = m_class_expression->name(); - VERIFY(!name.is_empty()); - auto class_constructor = TRY_OR_DISCARD(m_class_expression->class_definition_evaluation(interpreter, global_object, name, name)); + (void)TRY(binding_class_declaration_evaluation(interpreter, global_object)); - TRY_OR_DISCARD(initialize_bound_name(global_object, name, class_constructor, interpreter.lexical_environment())); - - return {}; + return normal_completion({}); } // 15.7.14 Runtime Semantics: ClassDefinitionEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-classdefinitionevaluation @@ -1533,13 +1443,10 @@ ThrowCompletionOr ClassExpression::class_definition_evaluation(Interprete Value super_class; auto reference = TRY(m_super_class->to_reference(interpreter, global_object)); - if (reference.is_valid_reference()) { super_class = TRY(reference.get_value(global_object)); } else { - super_class = m_super_class->execute(interpreter, global_object); - if (auto* exception = interpreter.exception()) - return throw_completion(exception->value()); + super_class = TRY(m_super_class->execute(interpreter, global_object)).release_value(); } vm.running_execution_context().lexical_environment = environment; @@ -1571,9 +1478,7 @@ ThrowCompletionOr ClassExpression::class_definition_evaluation(Interprete }; // FIXME: Step 14.a is done in the parser. But maybe it shouldn't? - Value class_constructor_value = m_constructor->execute(interpreter, global_object); - if (auto* exception = interpreter.exception()) - return throw_completion(exception->value()); + auto class_constructor_value = TRY(m_constructor->execute(interpreter, global_object)).release_value(); update_function_name(class_constructor_value, class_name); @@ -1666,6 +1571,16 @@ ThrowCompletionOr ClassExpression::class_definition_evaluation(Interprete return Value(class_constructor); } +ThrowCompletionOr ClassDeclaration::binding_class_declaration_evaluation(Interpreter& interpreter, GlobalObject& global_object) const +{ + auto class_name = m_class_expression->name(); + VERIFY(!class_name.is_empty()); + auto value = TRY(m_class_expression->class_definition_evaluation(interpreter, global_object, class_name, class_name)); + auto* env = interpreter.lexical_environment(); + TRY(initialize_bound_name(global_object, class_name, value, env)); + return value; +} + static void print_indent(int indent) { out("{}", String::repeated(' ', indent * 2)); @@ -2209,13 +2124,15 @@ void ForAwaitOfStatement::dump(int indent) const m_body->dump(indent + 1); } -Value Identifier::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion Identifier::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; - auto reference = TRY_OR_DISCARD(to_reference(interpreter, global_object)); + auto reference = TRY(interpreter.vm().resolve_binding(m_string)); - return TRY_OR_DISCARD(reference.get_value(global_object)); + // NOTE: The spec wants us to return the reference directly; this is not possible with ASTNode::execute() (short of letting it return a variant). + // So, instead of calling GetValue at the call site, we do it here. + return TRY(reference.get_value(global_object)); } void Identifier::dump(int indent) const @@ -2224,7 +2141,7 @@ void Identifier::dump(int indent) const outln("Identifier \"{}\"", m_string); } -Value PrivateIdentifier::execute(Interpreter&, GlobalObject&) const +Completion PrivateIdentifier::execute(Interpreter&, GlobalObject&) const { // Note: This should be handled by either the member expression this is part of // or the binary expression in the case of `#foo in bar`. @@ -2243,16 +2160,16 @@ void SpreadExpression::dump(int indent) const m_target->dump(indent + 1); } -Value SpreadExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion SpreadExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; return m_target->execute(interpreter, global_object); } -Value ThisExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion ThisExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; - return TRY_OR_DISCARD(interpreter.vm().resolve_this_binding(global_object)); + return interpreter.vm().resolve_this_binding(global_object); } void ThisExpression::dump(int indent) const @@ -2261,36 +2178,32 @@ void ThisExpression::dump(int indent) const } // 13.15.2 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-assignment-operators-runtime-semantics-evaluation -Value AssignmentExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion AssignmentExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; if (m_op == AssignmentOp::Assignment) { // AssignmentExpression : LeftHandSideExpression = AssignmentExpression return m_lhs.visit( - [&](NonnullRefPtr& lhs) -> JS::Value { - auto reference = TRY_OR_DISCARD(lhs->to_reference(interpreter, global_object)); + [&](NonnullRefPtr& lhs) -> ThrowCompletionOr { + auto reference = TRY(lhs->to_reference(interpreter, global_object)); Value rhs_result; if (lhs->is_identifier()) { auto& identifier_name = static_cast(*lhs).string(); - rhs_result = TRY_OR_DISCARD(interpreter.vm().named_evaluation_if_anonymous_function(global_object, m_rhs, identifier_name)); + rhs_result = TRY(interpreter.vm().named_evaluation_if_anonymous_function(global_object, m_rhs, identifier_name)); } else { - rhs_result = m_rhs->execute(interpreter, global_object); + rhs_result = TRY(m_rhs->execute(interpreter, global_object)).release_value(); } - if (interpreter.exception()) - return {}; - TRY_OR_DISCARD(reference.put_value(global_object, rhs_result)); + TRY(reference.put_value(global_object, rhs_result)); return rhs_result; }, - [&](NonnullRefPtr& pattern) -> JS::Value { - Value rhs_result = m_rhs->execute(interpreter, global_object); - if (interpreter.exception()) - return {}; + [&](NonnullRefPtr& pattern) -> ThrowCompletionOr { + auto rhs_result = TRY(m_rhs->execute(interpreter, global_object)).release_value(); - TRY_OR_DISCARD(interpreter.vm().destructuring_assignment_evaluation(pattern, rhs_result, global_object)); + TRY(interpreter.vm().destructuring_assignment_evaluation(pattern, rhs_result, global_object)); return rhs_result; }); @@ -2298,9 +2211,9 @@ Value AssignmentExpression::execute(Interpreter& interpreter, GlobalObject& glob VERIFY(m_lhs.has>()); auto& lhs_expression = *m_lhs.get>(); - auto reference = TRY_OR_DISCARD(lhs_expression.to_reference(interpreter, global_object)); + auto reference = TRY(lhs_expression.to_reference(interpreter, global_object)); - auto lhs_result = TRY_OR_DISCARD(reference.get_value(global_object)); + auto lhs_result = TRY(reference.get_value(global_object)); // AssignmentExpression : LeftHandSideExpression {&&=, ||=, ??=} AssignmentExpression if (m_op == AssignmentOp::AndAssignment || m_op == AssignmentOp::OrAssignment || m_op == AssignmentOp::NullishAssignment) { @@ -2324,60 +2237,55 @@ Value AssignmentExpression::execute(Interpreter& interpreter, GlobalObject& glob Value rhs_result; if (lhs_expression.is_identifier()) { auto& identifier_name = static_cast(lhs_expression).string(); - rhs_result = TRY_OR_DISCARD(interpreter.vm().named_evaluation_if_anonymous_function(global_object, m_rhs, identifier_name)); + rhs_result = TRY(interpreter.vm().named_evaluation_if_anonymous_function(global_object, m_rhs, identifier_name)); } else { - rhs_result = m_rhs->execute(interpreter, global_object); - - if (interpreter.exception()) - return {}; + rhs_result = TRY(m_rhs->execute(interpreter, global_object)).release_value(); } - TRY_OR_DISCARD(reference.put_value(global_object, rhs_result)); + TRY(reference.put_value(global_object, rhs_result)); return rhs_result; } // AssignmentExpression : LeftHandSideExpression AssignmentOperator AssignmentExpression - auto rhs_result = m_rhs->execute(interpreter, global_object); - if (interpreter.exception()) - return {}; + auto rhs_result = TRY(m_rhs->execute(interpreter, global_object)).release_value(); switch (m_op) { case AssignmentOp::AdditionAssignment: - rhs_result = TRY_OR_DISCARD(add(global_object, lhs_result, rhs_result)); + rhs_result = TRY(add(global_object, lhs_result, rhs_result)); break; case AssignmentOp::SubtractionAssignment: - rhs_result = TRY_OR_DISCARD(sub(global_object, lhs_result, rhs_result)); + rhs_result = TRY(sub(global_object, lhs_result, rhs_result)); break; case AssignmentOp::MultiplicationAssignment: - rhs_result = TRY_OR_DISCARD(mul(global_object, lhs_result, rhs_result)); + rhs_result = TRY(mul(global_object, lhs_result, rhs_result)); break; case AssignmentOp::DivisionAssignment: - rhs_result = TRY_OR_DISCARD(div(global_object, lhs_result, rhs_result)); + rhs_result = TRY(div(global_object, lhs_result, rhs_result)); break; case AssignmentOp::ModuloAssignment: - rhs_result = TRY_OR_DISCARD(mod(global_object, lhs_result, rhs_result)); + rhs_result = TRY(mod(global_object, lhs_result, rhs_result)); break; case AssignmentOp::ExponentiationAssignment: - rhs_result = TRY_OR_DISCARD(exp(global_object, lhs_result, rhs_result)); + rhs_result = TRY(exp(global_object, lhs_result, rhs_result)); break; case AssignmentOp::BitwiseAndAssignment: - rhs_result = TRY_OR_DISCARD(bitwise_and(global_object, lhs_result, rhs_result)); + rhs_result = TRY(bitwise_and(global_object, lhs_result, rhs_result)); break; case AssignmentOp::BitwiseOrAssignment: - rhs_result = TRY_OR_DISCARD(bitwise_or(global_object, lhs_result, rhs_result)); + rhs_result = TRY(bitwise_or(global_object, lhs_result, rhs_result)); break; case AssignmentOp::BitwiseXorAssignment: - rhs_result = TRY_OR_DISCARD(bitwise_xor(global_object, lhs_result, rhs_result)); + rhs_result = TRY(bitwise_xor(global_object, lhs_result, rhs_result)); break; case AssignmentOp::LeftShiftAssignment: - rhs_result = TRY_OR_DISCARD(left_shift(global_object, lhs_result, rhs_result)); + rhs_result = TRY(left_shift(global_object, lhs_result, rhs_result)); break; case AssignmentOp::RightShiftAssignment: - rhs_result = TRY_OR_DISCARD(right_shift(global_object, lhs_result, rhs_result)); + rhs_result = TRY(right_shift(global_object, lhs_result, rhs_result)); break; case AssignmentOp::UnsignedRightShiftAssignment: - rhs_result = TRY_OR_DISCARD(unsigned_right_shift(global_object, lhs_result, rhs_result)); + rhs_result = TRY(unsigned_right_shift(global_object, lhs_result, rhs_result)); break; case AssignmentOp::Assignment: case AssignmentOp::AndAssignment: @@ -2386,18 +2294,18 @@ Value AssignmentExpression::execute(Interpreter& interpreter, GlobalObject& glob VERIFY_NOT_REACHED(); } - TRY_OR_DISCARD(reference.put_value(global_object, rhs_result)); + TRY(reference.put_value(global_object, rhs_result)); return rhs_result; } -Value UpdateExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion UpdateExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; - auto reference = TRY_OR_DISCARD(m_argument->to_reference(interpreter, global_object)); - auto old_value = TRY_OR_DISCARD(reference.get_value(global_object)); - old_value = TRY_OR_DISCARD(old_value.to_numeric(global_object)); + auto reference = TRY(m_argument->to_reference(interpreter, global_object)); + auto old_value = TRY(reference.get_value(global_object)); + old_value = TRY(old_value.to_numeric(global_object)); Value new_value; switch (m_op) { @@ -2417,7 +2325,7 @@ Value UpdateExpression::execute(Interpreter& interpreter, GlobalObject& global_o VERIFY_NOT_REACHED(); } - TRY_OR_DISCARD(reference.put_value(global_object, new_value)); + TRY(reference.put_value(global_object, new_value)); return m_prefixed ? new_value : old_value; } @@ -2506,16 +2414,16 @@ void UpdateExpression::dump(int indent) const } } -Value VariableDeclaration::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion VariableDeclaration::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; for (auto& declarator : m_declarations) { if (auto* init = declarator.init()) { - TRY_OR_DISCARD(declarator.target().visit( + TRY(declarator.target().visit( [&](NonnullRefPtr const& id) -> ThrowCompletionOr { auto reference = TRY(id->to_reference(interpreter, global_object)); - auto initializer_result = TRY_OR_DISCARD(interpreter.vm().named_evaluation_if_anonymous_function(global_object, *init, id->string())); + auto initializer_result = TRY(interpreter.vm().named_evaluation_if_anonymous_function(global_object, *init, id->string())); VERIFY(!initializer_result.is_empty()); if (m_declaration_kind == DeclarationKind::Var) @@ -2524,9 +2432,7 @@ Value VariableDeclaration::execute(Interpreter& interpreter, GlobalObject& globa return reference.initialize_referenced_binding(global_object, initializer_result); }, [&](NonnullRefPtr const& pattern) -> ThrowCompletionOr { - auto initializer_result = init->execute(interpreter, global_object); - if (auto* exception = interpreter.exception()) - return throw_completion(exception->value()); + auto initializer_result = TRY(init->execute(interpreter, global_object)).release_value(); Environment* environment = m_declaration_kind == DeclarationKind::Var ? nullptr : interpreter.lexical_environment(); @@ -2535,14 +2441,14 @@ Value VariableDeclaration::execute(Interpreter& interpreter, GlobalObject& globa } else if (m_declaration_kind != DeclarationKind::Var) { VERIFY(declarator.target().has>()); auto& identifier = declarator.target().get>(); - auto reference = TRY_OR_DISCARD(identifier->to_reference(interpreter, global_object)); - TRY_OR_DISCARD(reference.initialize_referenced_binding(global_object, js_undefined())); + auto reference = TRY(identifier->to_reference(interpreter, global_object)); + TRY(reference.initialize_referenced_binding(global_object, js_undefined())); } } - return {}; + return normal_completion({}); } -Value VariableDeclarator::execute(Interpreter& interpreter, GlobalObject&) const +Completion VariableDeclarator::execute(Interpreter& interpreter, GlobalObject&) const { InterpreterNodeScope node_scope { interpreter, *this }; @@ -2624,7 +2530,7 @@ void ExpressionStatement::dump(int indent) const m_expression->dump(indent + 1); } -Value ObjectProperty::execute(Interpreter& interpreter, GlobalObject&) const +Completion ObjectProperty::execute(Interpreter& interpreter, GlobalObject&) const { InterpreterNodeScope node_scope { interpreter, *this }; @@ -2632,55 +2538,45 @@ Value ObjectProperty::execute(Interpreter& interpreter, GlobalObject&) const VERIFY_NOT_REACHED(); } -Value ObjectExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion ObjectExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; auto* object = Object::create(global_object, global_object.object_prototype()); for (auto& property : m_properties) { - auto key = property.key().execute(interpreter, global_object); - if (interpreter.exception()) - return {}; + auto key = TRY(property.key().execute(interpreter, global_object)).release_value(); if (property.type() == ObjectProperty::Type::Spread) { if (key.is_object() && is(key.as_object())) { auto& array_to_spread = static_cast(key.as_object()); for (auto& entry : array_to_spread.indexed_properties()) { - auto value = TRY_OR_DISCARD(array_to_spread.get(entry.index())); + auto value = TRY(array_to_spread.get(entry.index())); object->indexed_properties().put(entry.index(), value); - if (interpreter.exception()) - return {}; } } else if (key.is_object()) { auto& obj_to_spread = key.as_object(); for (auto& it : obj_to_spread.shape().property_table_ordered()) { if (it.value.attributes.is_enumerable()) { - object->define_direct_property(it.key, TRY_OR_DISCARD(obj_to_spread.get(it.key)), JS::default_attributes); - if (interpreter.exception()) - return {}; + auto value = TRY(obj_to_spread.get(it.key)); + object->define_direct_property(it.key, value, JS::default_attributes); } } } else if (key.is_string()) { auto& str_to_spread = key.as_string().string(); - for (size_t i = 0; i < str_to_spread.length(); i++) { + for (size_t i = 0; i < str_to_spread.length(); i++) object->define_direct_property(i, js_string(interpreter.heap(), str_to_spread.substring(i, 1)), JS::default_attributes); - if (interpreter.exception()) - return {}; - } } continue; } - auto value = property.value().execute(interpreter, global_object); - if (interpreter.exception()) - return {}; + auto value = TRY(property.value().execute(interpreter, global_object)).release_value(); if (value.is_function() && property.is_method()) static_cast(value.as_function()).set_home_object(object); - auto name = TRY_OR_DISCARD(get_function_name(global_object, key)); + auto name = TRY(get_function_name(global_object, key)); if (property.type() == ObjectProperty::Type::Getter) { name = String::formatted("get {}", name); } else if (property.type() == ObjectProperty::Type::Setter) { @@ -2705,10 +2601,8 @@ Value ObjectExpression::execute(Interpreter& interpreter, GlobalObject& global_o default: VERIFY_NOT_REACHED(); } - if (interpreter.exception()) - return {}; } - return object; + return Value { object }; } void MemberExpression::dump(int indent) const @@ -2729,12 +2623,12 @@ String MemberExpression::to_string_approximation() const return String::formatted("{}.{}", object_string, verify_cast(*m_property).string()); } -Value MemberExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion MemberExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; - auto reference = TRY_OR_DISCARD(to_reference(interpreter, global_object)); - return TRY_OR_DISCARD(reference.get_value(global_object)); + auto reference = TRY(to_reference(interpreter, global_object)); + return TRY(reference.get_value(global_object)); } bool MemberExpression::ends_in_private_name() const @@ -2779,13 +2673,12 @@ void OptionalChain::dump(int indent) const } } -Optional OptionalChain::to_reference_and_value(JS::Interpreter& interpreter, JS::GlobalObject& global_object) const +ThrowCompletionOr OptionalChain::to_reference_and_value(JS::Interpreter& interpreter, JS::GlobalObject& global_object) const { - // Note: This is wrapped in an optional to allow base_reference = ... - Optional base_reference = TRY_OR_DISCARD(m_base->to_reference(interpreter, global_object)); - auto base = base_reference->is_unresolvable() ? m_base->execute(interpreter, global_object) : TRY_OR_DISCARD(base_reference->get_value(global_object)); - if (interpreter.exception()) - return {}; + auto base_reference = TRY(m_base->to_reference(interpreter, global_object)); + auto base = base_reference.is_unresolvable() + ? TRY(m_base->execute(interpreter, global_object)).release_value() + : TRY(base_reference.get_value(global_object)); for (auto& reference : m_references) { auto is_optional = reference.visit([](auto& ref) { return ref.mode; }) == Mode::Optional; @@ -2795,54 +2688,48 @@ Optional OptionalChain::to_reference_and_value auto expression = reference.visit( [&](Call const& call) -> NonnullRefPtr { return create_ast_node(source_range(), - create_ast_node(source_range(), *base_reference, base), + create_ast_node(source_range(), base_reference, base), call.arguments); }, [&](ComputedReference const& ref) -> NonnullRefPtr { return create_ast_node(source_range(), - create_ast_node(source_range(), *base_reference, base), + create_ast_node(source_range(), base_reference, base), ref.expression, true); }, [&](MemberReference const& ref) -> NonnullRefPtr { return create_ast_node(source_range(), - create_ast_node(source_range(), *base_reference, base), + create_ast_node(source_range(), base_reference, base), ref.identifier, false); }, [&](PrivateMemberReference const& ref) -> NonnullRefPtr { return create_ast_node(source_range(), - create_ast_node(source_range(), *base_reference, base), + create_ast_node(source_range(), base_reference, base), ref.private_identifier, false); }); if (is(*expression)) { base_reference = JS::Reference {}; - base = expression->execute(interpreter, global_object); + base = TRY(expression->execute(interpreter, global_object)).release_value(); } else { - base_reference = TRY_OR_DISCARD(expression->to_reference(interpreter, global_object)); - base = TRY_OR_DISCARD(base_reference->get_value(global_object)); + base_reference = TRY(expression->to_reference(interpreter, global_object)); + base = TRY(base_reference.get_value(global_object)); } - if (interpreter.exception()) - return {}; } - return ReferenceAndValue { base_reference.release_value(), base }; + return ReferenceAndValue { move(base_reference), base }; } -Value OptionalChain::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion OptionalChain::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; - if (auto result = to_reference_and_value(interpreter, global_object); result.has_value()) - return result.release_value().value; - return {}; + return TRY(to_reference_and_value(interpreter, global_object)).value; } ThrowCompletionOr OptionalChain::to_reference(Interpreter& interpreter, GlobalObject& global_object) const { - if (auto result = to_reference_and_value(interpreter, global_object); result.has_value()) - return result.release_value().reference; - return JS::Reference {}; + return TRY(to_reference_and_value(interpreter, global_object)).reference; } void MetaProperty::dump(int indent) const @@ -2858,15 +2745,15 @@ void MetaProperty::dump(int indent) const outln("{} {}", class_name(), name); } -Value MetaProperty::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion MetaProperty::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; if (m_type == MetaProperty::Type::NewTarget) return interpreter.vm().get_new_target(); if (m_type == MetaProperty::Type::ImportMeta) { - interpreter.vm().throw_exception(global_object, ErrorType::NotImplemented, "'import.meta' in modules"); - return {}; + // TODO: Implement me :^) + return interpreter.vm().throw_completion(global_object, ErrorType::NotImplemented, "'import.meta' in modules"); } VERIFY_NOT_REACHED(); @@ -2884,48 +2771,47 @@ void ImportCall::dump(int indent) const } } -Value ImportCall::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion ImportCall::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; - interpreter.vm().throw_exception(global_object, ErrorType::NotImplemented, "'import(...)' in modules"); - return {}; + return interpreter.vm().throw_completion(global_object, ErrorType::NotImplemented, "'import(...)' in modules"); } -Value StringLiteral::execute(Interpreter& interpreter, GlobalObject&) const +Completion StringLiteral::execute(Interpreter& interpreter, GlobalObject&) const { InterpreterNodeScope node_scope { interpreter, *this }; - return js_string(interpreter.heap(), m_value); + return Value { js_string(interpreter.heap(), m_value) }; } -Value NumericLiteral::execute(Interpreter& interpreter, GlobalObject&) const +Completion NumericLiteral::execute(Interpreter& interpreter, GlobalObject&) const { InterpreterNodeScope node_scope { interpreter, *this }; return Value(m_value); } -Value BigIntLiteral::execute(Interpreter& interpreter, GlobalObject&) const +Completion BigIntLiteral::execute(Interpreter& interpreter, GlobalObject&) const { InterpreterNodeScope node_scope { interpreter, *this }; Crypto::SignedBigInteger integer; if (m_value[0] == '0' && m_value.length() >= 3) { if (m_value[1] == 'x' || m_value[1] == 'X') { - return js_bigint(interpreter.heap(), Crypto::SignedBigInteger::from_base(16, m_value.substring(2, m_value.length() - 3))); + return Value { js_bigint(interpreter.heap(), Crypto::SignedBigInteger::from_base(16, m_value.substring(2, m_value.length() - 3))) }; } else if (m_value[1] == 'o' || m_value[1] == 'O') { - return js_bigint(interpreter.heap(), Crypto::SignedBigInteger::from_base(8, m_value.substring(2, m_value.length() - 3))); + return Value { js_bigint(interpreter.heap(), Crypto::SignedBigInteger::from_base(8, m_value.substring(2, m_value.length() - 3))) }; } else if (m_value[1] == 'b' || m_value[1] == 'B') { - return js_bigint(interpreter.heap(), Crypto::SignedBigInteger::from_base(2, m_value.substring(2, m_value.length() - 3))); + return Value { js_bigint(interpreter.heap(), Crypto::SignedBigInteger::from_base(2, m_value.substring(2, m_value.length() - 3))) }; } } - return js_bigint(interpreter.heap(), Crypto::SignedBigInteger::from_base(10, m_value.substring(0, m_value.length() - 1))); + return Value { js_bigint(interpreter.heap(), Crypto::SignedBigInteger::from_base(10, m_value.substring(0, m_value.length() - 1))) }; } -Value BooleanLiteral::execute(Interpreter& interpreter, GlobalObject&) const +Completion BooleanLiteral::execute(Interpreter& interpreter, GlobalObject&) const { InterpreterNodeScope node_scope { interpreter, *this }; return Value(m_value); } -Value NullLiteral::execute(Interpreter& interpreter, GlobalObject&) const +Completion NullLiteral::execute(Interpreter& interpreter, GlobalObject&) const { InterpreterNodeScope node_scope { interpreter, *this }; return js_null(); @@ -2937,12 +2823,12 @@ void RegExpLiteral::dump(int indent) const outln("{} (/{}/{})", class_name(), pattern(), flags()); } -Value RegExpLiteral::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion RegExpLiteral::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; Regex regex(parsed_regex(), parsed_pattern(), parsed_flags()); - return RegExpObject::create(global_object, move(regex), pattern(), flags()); + return Value { RegExpObject::create(global_object, move(regex), pattern(), flags()) }; } void ArrayExpression::dump(int indent) const @@ -2958,7 +2844,7 @@ void ArrayExpression::dump(int indent) const } } -Value ArrayExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion ArrayExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; @@ -2968,12 +2854,10 @@ Value ArrayExpression::execute(Interpreter& interpreter, GlobalObject& global_ob for (auto& element : m_elements) { auto value = Value(); if (element) { - value = element->execute(interpreter, global_object); - if (interpreter.exception()) - return {}; + value = TRY(element->execute(interpreter, global_object)).release_value(); if (is(*element)) { - (void)TRY_OR_DISCARD(get_iterator_values(global_object, value, [&](Value iterator_value) -> Optional { + (void)TRY(get_iterator_values(global_object, value, [&](Value iterator_value) -> Optional { array->indexed_properties().put(index++, iterator_value, default_attributes); return {}; })); @@ -2982,7 +2866,7 @@ Value ArrayExpression::execute(Interpreter& interpreter, GlobalObject& global_ob } array->indexed_properties().put(index++, value, default_attributes); } - return array; + return Value { array }; } void TemplateLiteral::dump(int indent) const @@ -2992,21 +2876,19 @@ void TemplateLiteral::dump(int indent) const expression.dump(indent + 1); } -Value TemplateLiteral::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion TemplateLiteral::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; StringBuilder string_builder; for (auto& expression : m_expressions) { - auto expr = expression.execute(interpreter, global_object); - if (interpreter.exception()) - return {}; - auto string = TRY_OR_DISCARD(expr.to_string(global_object)); + auto sub = TRY(expression.execute(interpreter, global_object)).release_value(); + auto string = TRY(sub.to_string(global_object)); string_builder.append(string); } - return js_string(interpreter.heap(), string_builder.build()); + return Value { js_string(interpreter.heap(), string_builder.build()) }; } void TaggedTemplateLiteral::dump(int indent) const @@ -3020,27 +2902,18 @@ void TaggedTemplateLiteral::dump(int indent) const m_template_literal->dump(indent + 2); } -Value TaggedTemplateLiteral::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion TaggedTemplateLiteral::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; auto& vm = interpreter.vm(); - auto tag = m_tag->execute(interpreter, global_object); - if (vm.exception()) - return {}; - if (!tag.is_function()) { - vm.throw_exception(global_object, ErrorType::NotAFunction, tag.to_string_without_side_effects()); - return {}; - } - auto& tag_function = tag.as_function(); + auto tag = TRY(m_tag->execute(interpreter, global_object)).release_value(); auto& expressions = m_template_literal->expressions(); auto* strings = MUST(Array::create(global_object, 0)); MarkedValueList arguments(vm.heap()); arguments.append(strings); for (size_t i = 0; i < expressions.size(); ++i) { - auto value = expressions[i].execute(interpreter, global_object); - if (vm.exception()) - return {}; + auto value = TRY(expressions[i].execute(interpreter, global_object)).release_value(); // tag`${foo}` -> "", foo, "" -> tag(["", ""], foo) // tag`foo${bar}baz${qux}` -> "foo", bar, "baz", qux, "" -> tag(["foo", "baz", ""], bar, qux) if (i % 2 == 0) { @@ -3052,13 +2925,11 @@ Value TaggedTemplateLiteral::execute(Interpreter& interpreter, GlobalObject& glo auto* raw_strings = MUST(Array::create(global_object, 0)); for (auto& raw_string : m_template_literal->raw_strings()) { - auto value = raw_string.execute(interpreter, global_object); - if (vm.exception()) - return {}; + auto value = TRY(raw_string.execute(interpreter, global_object)).release_value(); raw_strings->indexed_properties().append(value); } strings->define_direct_property(vm.names.raw, raw_strings, 0); - return TRY_OR_DISCARD(vm.call(tag_function, js_undefined(), move(arguments))); + return call(global_object, tag, js_undefined(), move(arguments)); } void TryStatement::dump(int indent) const @@ -3112,7 +2983,8 @@ void TryStatement::add_label(FlyString string) m_block->add_label(move(string)); } -Value TryStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const +// 14.15.3 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-try-statement-runtime-semantics-evaluation +Completion TryStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; @@ -3180,10 +3052,10 @@ Value TryStatement::execute(Interpreter& interpreter, GlobalObject& global_objec } } - return result.value_or(js_undefined()); + return result.update_empty(js_undefined()); } -Value CatchClause::execute(Interpreter& interpreter, GlobalObject&) const +Completion CatchClause::execute(Interpreter& interpreter, GlobalObject&) const { InterpreterNodeScope node_scope { interpreter, *this }; @@ -3192,18 +3064,17 @@ Value CatchClause::execute(Interpreter& interpreter, GlobalObject&) const return {}; } -Value ThrowStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion ThrowStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; - auto value = m_argument->execute(interpreter, global_object); - if (interpreter.vm().exception()) - return {}; + auto value = TRY(m_argument->execute(interpreter, global_object)).release_value(); + // TODO: Remove this once we get rid of VM::exception() interpreter.vm().throw_exception(global_object, value); - return {}; + return throw_completion(value); } // 14.12.2 Runtime Semantics: CaseBlockEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-caseblockevaluation -Value SwitchStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion SwitchStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { // FIXME: This needs a massive refactoring, ideally once we start using continue, break, and return completions. // Instead of having an optional test expression, SwitchCase should be split into CaseClause and DefaultClause. @@ -3211,9 +3082,7 @@ Value SwitchStatement::execute(Interpreter& interpreter, GlobalObject& global_ob InterpreterNodeScope node_scope { interpreter, *this }; - auto discriminant_result = m_discriminant->execute(interpreter, global_object); - if (interpreter.exception()) - return {}; + auto discriminant_result = TRY(m_discriminant->execute(interpreter, global_object)).release_value(); // Optimization: Avoid creating a lexical environment if there are no lexical declarations. Optional> lexical_environment_changer; @@ -3228,9 +3097,7 @@ Value SwitchStatement::execute(Interpreter& interpreter, GlobalObject& global_ob for (size_t i = 0; i < m_cases.size(); ++i) { auto& switch_case = m_cases[i]; if (switch_case.test()) { - auto test_result = switch_case.test()->execute(interpreter, global_object); - if (interpreter.exception()) - return {}; + auto test_result = TRY(switch_case.test()->execute(interpreter, global_object)).release_value(); if (is_strictly_equal(discriminant_result, test_result)) { first_passing_case = i; break; @@ -3259,11 +3126,9 @@ Value SwitchStatement::execute(Interpreter& interpreter, GlobalObject& global_ob for (size_t i = first_passing_case.value(); i < m_cases.size(); ++i) { auto& switch_case = m_cases[i]; for (auto& statement : switch_case.children()) { - auto value = statement.execute(interpreter, global_object); - if (!value.is_empty()) - last_value = value; - if (interpreter.exception()) - return {}; + auto value = TRY(statement.execute(interpreter, global_object)); + if (value.has_value()) + last_value = *value; if (interpreter.vm().should_unwind()) { if (interpreter.vm().should_unwind_until(ScopeType::Continuable, m_labels)) { // No stop_unwind(), the outer loop will handle that - we just need to break out of the switch/case. @@ -3280,7 +3145,7 @@ Value SwitchStatement::execute(Interpreter& interpreter, GlobalObject& global_ob return last_value; } -Value SwitchCase::execute(Interpreter& interpreter, GlobalObject&) const +Completion SwitchCase::execute(Interpreter& interpreter, GlobalObject&) const { InterpreterNodeScope node_scope { interpreter, *this }; @@ -3289,18 +3154,22 @@ Value SwitchCase::execute(Interpreter& interpreter, GlobalObject&) const return {}; } -Value BreakStatement::execute(Interpreter& interpreter, GlobalObject&) const +Completion BreakStatement::execute(Interpreter& interpreter, GlobalObject&) const { InterpreterNodeScope node_scope { interpreter, *this }; + + // TODO: Return break completion interpreter.vm().unwind(ScopeType::Breakable, m_target_label); - return {}; + return normal_completion({}); } -Value ContinueStatement::execute(Interpreter& interpreter, GlobalObject&) const +Completion ContinueStatement::execute(Interpreter& interpreter, GlobalObject&) const { InterpreterNodeScope node_scope { interpreter, *this }; + + // TODO: Return continue completion interpreter.vm().unwind(ScopeType::Continuable, m_target_label); - return {}; + return normal_completion({}); } void SwitchStatement::dump(int indent) const @@ -3326,22 +3195,16 @@ void SwitchCase::dump(int indent) const ScopeNode::dump(indent + 2); } -Value ConditionalExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion ConditionalExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; - auto test_result = m_test->execute(interpreter, global_object); - if (interpreter.exception()) - return {}; - Value result; + auto test_result = TRY(m_test->execute(interpreter, global_object)).release_value(); if (test_result.to_boolean()) { - result = m_consequent->execute(interpreter, global_object); + return m_consequent->execute(interpreter, global_object); } else { - result = m_alternate->execute(interpreter, global_object); + return m_alternate->execute(interpreter, global_object); } - if (interpreter.exception()) - return {}; - return result; } void ConditionalExpression::dump(int indent) const @@ -3365,24 +3228,21 @@ void SequenceExpression::dump(int indent) const expression.dump(indent + 1); } -Value SequenceExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion SequenceExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; Value last_value; - for (auto& expression : m_expressions) { - last_value = expression.execute(interpreter, global_object); - if (interpreter.exception()) - return {}; - } - return last_value; + for (auto const& expression : m_expressions) + last_value = TRY(expression.execute(interpreter, global_object)).release_value(); + return { move(last_value) }; } -Value DebuggerStatement::execute(Interpreter& interpreter, GlobalObject&) const +Completion DebuggerStatement::execute(Interpreter& interpreter, GlobalObject&) const { InterpreterNodeScope node_scope { interpreter, *this }; // Sorry, no JavaScript debugger available (yet)! - return {}; + return normal_completion({}); } void ScopeNode::for_each_lexically_scoped_declaration(IteratorOrVoidFunction&& callback) const @@ -3471,21 +3331,19 @@ void ScopeNode::add_hoisted_function(NonnullRefPtr declarat m_functions_hoistable_with_annexB_extension.append(move(declaration)); } -Value ImportStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion ImportStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; dbgln("Modules are not fully supported yet!"); - interpreter.vm().throw_exception(global_object, ErrorType::NotImplemented, "'import' in modules"); - return {}; + return interpreter.vm().throw_completion(global_object, ErrorType::NotImplemented, "'import' in modules"); } -Value ExportStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const +Completion ExportStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { InterpreterNodeScope node_scope { interpreter, *this }; - if (m_statement) - return m_statement->execute(interpreter, global_object); + return m_statement->execute(interpreter, global_object); - return {}; + return normal_completion({}); } static void dump_assert_clauses(ModuleRequest const& request) diff --git a/Userland/Libraries/LibJS/AST.h b/Userland/Libraries/LibJS/AST.h index 9e2ee6dd0b..c97e161269 100644 --- a/Userland/Libraries/LibJS/AST.h +++ b/Userland/Libraries/LibJS/AST.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2020-2021, Andreas Kling - * Copyright (c) 2020, Linus Groh + * Copyright (c) 2020-2022, Linus Groh * Copyright (c) 2021, David Tuin * * SPDX-License-Identifier: BSD-2-Clause @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -44,7 +45,7 @@ create_ast_node(SourceRange range, Args&&... args) class ASTNode : public RefCounted { public: virtual ~ASTNode() { } - virtual Value execute(Interpreter&, GlobalObject&) const = 0; + virtual Completion execute(Interpreter&, GlobalObject&) const = 0; virtual void generate_bytecode(Bytecode::Generator&) const; virtual void dump(int indent) const; @@ -107,7 +108,7 @@ public: : Statement(source_range) { } - Value execute(Interpreter&, GlobalObject&) const override { return {}; } + Completion execute(Interpreter&, GlobalObject&) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; }; @@ -117,7 +118,7 @@ public: : Statement(source_range) { } - Value execute(Interpreter&, GlobalObject&) const override { return {}; } + Completion execute(Interpreter&, GlobalObject&) const override { return {}; } }; class ExpressionStatement final : public Statement { @@ -128,7 +129,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -177,7 +178,7 @@ public: virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; - Value evaluate_statements(Interpreter& interpreter, GlobalObject& global_object) const; + Completion evaluate_statements(Interpreter& interpreter, GlobalObject& global_object) const; void add_var_scoped_declaration(NonnullRefPtr variables); void add_lexical_declaration(NonnullRefPtr variables); @@ -254,7 +255,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; @@ -296,7 +297,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; @@ -323,7 +324,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; bool is_strict_mode() const { return m_is_strict_mode; } void set_strict_mode() { m_is_strict_mode = true; } @@ -363,7 +364,7 @@ public: : ScopeNode(source_range) { } - Value execute(Interpreter& interpreter, GlobalObject& object) const override; + Completion execute(Interpreter& interpreter, GlobalObject& object) const override; }; class FunctionBody final : public ScopeNode { @@ -377,7 +378,7 @@ public: bool in_strict_mode() const { return m_in_strict_mode; } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; private: bool m_in_strict_mode { false }; @@ -413,7 +414,7 @@ public: : Declaration(source_range) { } - Value execute(Interpreter&, GlobalObject&) const override { return {}; } + Completion execute(Interpreter&, GlobalObject&) const override { return {}; } void for_each_bound_name(IteratorOrVoidFunction) const override { @@ -516,7 +517,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -542,7 +543,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -562,7 +563,7 @@ public: { } - Value execute(Interpreter&, GlobalObject&) const override { return {}; } + Completion execute(Interpreter&, GlobalObject&) const override { return {}; } }; class YieldExpression final : public Expression { @@ -577,7 +578,7 @@ public: Expression const* argument() const { return m_argument; } bool is_yield_from() const { return m_is_yield_from; } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -594,7 +595,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -612,7 +613,7 @@ public: Expression const* argument() const { return m_argument; } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -634,7 +635,7 @@ public: Statement const& consequent() const { return *m_consequent; } Statement const* alternate() const { return m_alternate; } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -656,7 +657,7 @@ public: Expression const& test() const { return *m_test; } Statement const& body() const { return *m_body; } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -677,7 +678,7 @@ public: Expression const& test() const { return *m_test; } Statement const& body() const { return *m_body; } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -698,7 +699,7 @@ public: Expression const& object() const { return *m_object; } Statement const& body() const { return *m_body; } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; private: @@ -722,7 +723,7 @@ public: Expression const* update() const { return m_update; } Statement const& body() const { return *m_body; } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -747,7 +748,7 @@ public: Expression const& rhs() const { return *m_rhs; } Statement const& body() const { return *m_body; } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; private: @@ -770,7 +771,7 @@ public: Expression const& rhs() const { return *m_rhs; } Statement const& body() const { return *m_body; } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; private: @@ -789,7 +790,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; private: @@ -833,7 +834,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -859,7 +860,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -888,7 +889,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -907,7 +908,7 @@ public: } virtual void dump(int indent) const override; - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; private: @@ -930,7 +931,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -946,7 +947,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -962,7 +963,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -979,7 +980,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -998,7 +999,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; }; @@ -1015,7 +1016,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -1044,7 +1045,7 @@ public: FlyString const& string() const { return m_string; } void set_lexically_bound_function_argument_index(size_t index) { m_lexically_bound_function_argument = index; } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual ThrowCompletionOr to_reference(Interpreter&, GlobalObject&) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -1067,7 +1068,7 @@ public: FlyString const& string() const { return m_string; } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; private: @@ -1082,7 +1083,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; enum class ElementKind { Method, @@ -1192,7 +1193,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual bool is_super_expression() const override { return true; } @@ -1212,7 +1213,7 @@ public: StringView name() const { return m_name; } RefPtr constructor() const { return m_constructor; } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; bool has_name() const { return !m_name.is_empty(); } @@ -1236,7 +1237,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -1246,6 +1247,8 @@ public: StringView name() const { return m_class_expression->name(); } + ThrowCompletionOr binding_class_declaration_evaluation(Interpreter& interpreter, GlobalObject& global_object) const; + private: NonnullRefPtr m_class_expression; }; @@ -1258,7 +1261,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; private: @@ -1271,7 +1274,7 @@ public: : Expression(source_range) { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; }; @@ -1290,14 +1293,14 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; Expression const& callee() const { return m_callee; } protected: - void throw_type_error_for_callee(Interpreter&, GlobalObject&, Value callee_value, StringView call_type) const; + Completion throw_type_error_for_callee(Interpreter&, GlobalObject&, Value callee_value, StringView call_type) const; NonnullRefPtr m_callee; Vector const m_arguments; @@ -1307,8 +1310,7 @@ private: Value this_value; Value callee; }; - - ThisAndCallee compute_this_and_callee(Interpreter&, GlobalObject&, Reference const&) const; + ThrowCompletionOr compute_this_and_callee(Interpreter&, GlobalObject&, Reference const&) const; }; class NewExpression final : public CallExpression { @@ -1318,7 +1320,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual bool is_new_expression() const override { return true; } }; @@ -1331,7 +1333,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; private: @@ -1375,7 +1377,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -1400,7 +1402,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -1441,7 +1443,7 @@ public: auto& target() const { return m_target; } Expression const* init() const { return m_init; } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; private: @@ -1460,7 +1462,7 @@ public: DeclarationKind declaration_kind() const { return m_declaration_kind; } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -1506,7 +1508,7 @@ public: bool is_method() const { return m_is_method; } virtual void dump(int indent) const override; - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; private: NonnullRefPtr m_key; @@ -1524,7 +1526,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -1545,7 +1547,7 @@ public: Vector> const& elements() const { return m_elements; } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -1568,7 +1570,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -1589,7 +1591,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -1608,7 +1610,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual ThrowCompletionOr to_reference(Interpreter&, GlobalObject&) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -1662,7 +1664,7 @@ public: { } - virtual Value execute(Interpreter& interpreter, GlobalObject& global_object) const override; + virtual Completion execute(Interpreter& interpreter, GlobalObject& global_object) const override; virtual ThrowCompletionOr to_reference(Interpreter& interpreter, GlobalObject& global_object) const override; virtual void dump(int indent) const override; @@ -1671,7 +1673,7 @@ private: JS::Reference reference; Value value; }; - Optional to_reference_and_value(Interpreter&, GlobalObject&) const; + ThrowCompletionOr to_reference_and_value(Interpreter&, GlobalObject&) const; NonnullRefPtr m_base; Vector m_references; @@ -1690,7 +1692,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; private: @@ -1707,7 +1709,7 @@ public: } virtual void dump(int indent) const override; - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; private: NonnullRefPtr m_specifier; @@ -1725,7 +1727,7 @@ public: } virtual void dump(int indent) const override; - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; private: @@ -1754,7 +1756,7 @@ public: BlockStatement const& body() const { return m_body; } virtual void dump(int indent) const override; - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; private: Variant> m_parameter; @@ -1776,7 +1778,7 @@ public: BlockStatement const* finalizer() const { return m_finalizer; } virtual void dump(int indent) const override; - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; void add_label(FlyString string) override; @@ -1797,7 +1799,7 @@ public: Expression const& argument() const { return m_argument; } virtual void dump(int indent) const override; - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; private: @@ -1815,7 +1817,7 @@ public: Expression const* test() const { return m_test; } virtual void dump(int indent) const override; - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; private: RefPtr m_test; @@ -1830,7 +1832,7 @@ public: } virtual void dump(int indent) const override; - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; void add_case(NonnullRefPtr switch_case) { m_cases.append(move(switch_case)); } @@ -1848,7 +1850,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; FlyString const& target_label() const { return m_target_label; } virtual void generate_bytecode(Bytecode::Generator&) const override; @@ -1865,7 +1867,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; FlyString const& target_label() const { return m_target_label; } @@ -1881,7 +1883,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override; + virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void generate_bytecode(Bytecode::Generator&) const override; }; @@ -1894,7 +1896,7 @@ public: { } - virtual Value execute(Interpreter&, GlobalObject&) const override { return m_value; } + virtual Completion execute(Interpreter&, GlobalObject&) const override { return m_value; } virtual ThrowCompletionOr to_reference(Interpreter&, GlobalObject&) const override { return m_reference; } private: diff --git a/Userland/Libraries/LibJS/Bytecode/Op.cpp b/Userland/Libraries/LibJS/Bytecode/Op.cpp index 6e1a620361..2665d6e9f6 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Op.cpp @@ -315,13 +315,10 @@ void Jump::execute_impl(Bytecode::Interpreter& interpreter) const void ResolveThisBinding::execute_impl(Bytecode::Interpreter& interpreter) const { - auto this_binding_or_error = interpreter.vm().resolve_this_binding(interpreter.global_object()); - if (this_binding_or_error.is_throw_completion()) { - interpreter.vm().throw_exception(interpreter.global_object(), this_binding_or_error.release_error().value()); + auto value_or_error = interpreter.vm().resolve_this_binding(interpreter.global_object()); + if (value_or_error.is_error()) return; - } - - interpreter.accumulator() = this_binding_or_error.release_value(); + interpreter.accumulator() = value_or_error.release_value(); } void Jump::replace_references_impl(BasicBlock const& from, BasicBlock const& to) diff --git a/Userland/Libraries/LibJS/Interpreter.cpp b/Userland/Libraries/LibJS/Interpreter.cpp index 5ad5f5c48c..fc215875a8 100644 --- a/Userland/Libraries/LibJS/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Interpreter.cpp @@ -59,8 +59,8 @@ void Interpreter::run(GlobalObject& global_object, const Program& program) execution_context.realm = &realm(); execution_context.is_strict_mode = program.is_strict_mode(); MUST(vm.push_execution_context(execution_context, global_object)); - auto value = program.execute(*this, global_object); - vm.set_last_value(Badge {}, value.value_or(js_undefined())); + auto completion = program.execute(*this, global_object); + vm.set_last_value(Badge {}, completion.value().value_or(js_undefined())); // FIXME: We unconditionally stop the unwind here this should be done using completions leaving // the VM in a cleaner state after executing. For example it does still store the exception. diff --git a/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp b/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp index 3fc1810ee3..cc11fa17a1 100644 --- a/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp +++ b/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2021, Linus Groh + * Copyright (c) 2020-2022, Linus Groh * Copyright (c) 2021, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause @@ -564,7 +564,7 @@ ThrowCompletionOr perform_eval(Value x, GlobalObject& caller_realm, Calle TemporaryChange scope_change_strict(vm.running_execution_context().is_strict_mode, strict_eval); - Value eval_result; + Optional eval_result; if (auto* bytecode_interpreter = Bytecode::Interpreter::current()) { auto executable = JS::Bytecode::Generator::generate(program); @@ -572,16 +572,16 @@ ThrowCompletionOr perform_eval(Value x, GlobalObject& caller_realm, Calle if (JS::Bytecode::g_dump_bytecode) executable.dump(); eval_result = TRY(bytecode_interpreter->run(executable)); + // Turn potentially empty JS::Value from the bytecode interpreter into an empty Optional + if (eval_result.has_value() && eval_result->is_empty()) + eval_result = {}; } else { auto& ast_interpreter = vm.interpreter(); // FIXME: We need to use evaluate_statements() here because Program::execute() calls global_declaration_instantiation() when it shouldn't - eval_result = program->evaluate_statements(ast_interpreter, caller_realm); + eval_result = TRY(program->evaluate_statements(ast_interpreter, caller_realm)); } - if (auto* exception = vm.exception()) - return throw_completion(exception->value()); - else - return eval_result.value_or(js_undefined()); + return eval_result.value_or(js_undefined()); } // 19.2.1.3 EvalDeclarationInstantiation ( body, varEnv, lexEnv, privateEnv, strict ), https://tc39.es/ecma262/#sec-evaldeclarationinstantiation diff --git a/Userland/Libraries/LibJS/Runtime/AsyncFunctionConstructor.cpp b/Userland/Libraries/LibJS/Runtime/AsyncFunctionConstructor.cpp index f069c6545e..efdf6ad120 100644 --- a/Userland/Libraries/LibJS/Runtime/AsyncFunctionConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/AsyncFunctionConstructor.cpp @@ -50,9 +50,7 @@ ThrowCompletionOr AsyncFunctionConstructor::construct(FunctionObject& n } VM::InterpreterExecutionScope scope(*interpreter); - auto result = function->execute(*interpreter, global_object()); - if (auto* exception = vm.exception()) - return throw_completion(exception->value()); + auto result = TRY(function->execute(*interpreter, global_object())).release_value(); VERIFY(result.is_object() && is(result.as_object())); return &result.as_object(); } diff --git a/Userland/Libraries/LibJS/Runtime/AsyncGeneratorFunctionConstructor.cpp b/Userland/Libraries/LibJS/Runtime/AsyncGeneratorFunctionConstructor.cpp index 4f03fcee25..485b24b69b 100644 --- a/Userland/Libraries/LibJS/Runtime/AsyncGeneratorFunctionConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/AsyncGeneratorFunctionConstructor.cpp @@ -54,9 +54,7 @@ ThrowCompletionOr AsyncGeneratorFunctionConstructor::construct(Function } VM::InterpreterExecutionScope scope(*interpreter); - auto result = function->execute(*interpreter, global_object()); - if (auto* exception = vm.exception()) - return throw_completion(exception->value()); + auto result = TRY(function->execute(*interpreter, global_object())).release_value(); VERIFY(result.is_object() && is(result.as_object())); return &result.as_object(); } diff --git a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp index 7c255e1f2b..4846757f5b 100644 --- a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp @@ -431,9 +431,7 @@ ThrowCompletionOr ECMAScriptFunctionObject::function_declaration_instantia } else if (parameter.default_value) { // FIXME: Support default arguments in the bytecode world! if (interpreter) - argument_value = parameter.default_value->execute(*interpreter, global_object()); - if (auto* exception = vm.exception()) - return throw_completion(exception->value()); + argument_value = TRY(parameter.default_value->execute(*interpreter, global_object())).release_value(); } else { argument_value = js_undefined(); } @@ -715,27 +713,26 @@ void ECMAScriptFunctionObject::async_block_start(PromiseCapability const& promis // c. Remove asyncContext from the execution context stack and restore the execution context that is at the top of the execution context stack as the running execution context. vm.pop_execution_context(); - // NOTE: Running the AST node should eventually return a completion. - // Until it does, we assume "return" and include the undefined fallback from the call site. + // NOTE: Eventually we'll distinguish between normal and return completion. + // For now, we assume "return" and include the undefined fallback from the call site. // d. If result.[[Type]] is normal, then if (false) { // i. Perform ! Call(promiseCapability.[[Resolve]], undefined, « undefined »). MUST(call(global_object, promise_capability.resolve, js_undefined(), js_undefined())); } // e. Else if result.[[Type]] is return, then - else if (!vm.exception()) { + else if (result.type() == Completion::Type::Return || result.type() == Completion::Type::Normal) { // i. Perform ! Call(promiseCapability.[[Resolve]], undefined, « result.[[Value]] »). - MUST(call(global_object, promise_capability.resolve, js_undefined(), result.value_or(js_undefined()))); + MUST(call(global_object, promise_capability.resolve, js_undefined(), result.value().value_or(js_undefined()))); } // f. Else, else { // i. Assert: result.[[Type]] is throw. // ii. Perform ! Call(promiseCapability.[[Reject]], undefined, « result.[[Value]] »). - auto reason = vm.exception()->value(); vm.clear_exception(); vm.stop_unwind(); - MUST(call(global_object, promise_capability.reject, js_undefined(), reason)); + MUST(call(global_object, promise_capability.reject, js_undefined(), *result.value())); } // g. Return. return js_undefined(); @@ -823,11 +820,9 @@ Completion ECMAScriptFunctionObject::ordinary_call_evaluate_body() if (m_kind == FunctionKind::Regular) { TRY(function_declaration_instantiation(ast_interpreter)); - auto result = m_ecmascript_code->execute(*ast_interpreter, global_object()); - if (auto* exception = vm.exception()) - return throw_completion(exception->value()); - // NOTE: Running the AST node should eventually return a completion. - // Until it does, we assume "return" and include the undefined fallback from the call site. + auto result = TRY(m_ecmascript_code->execute(*ast_interpreter, global_object())); + // NOTE: Once 'return' completions are being used, we can just return the completion from execute() directly. + // For now, we assume "return" and include the undefined fallback from the call site. return { Completion::Type::Return, result.value_or(js_undefined()), {} }; } else if (m_kind == FunctionKind::Async) { // 1. Let promiseCapability be ! NewPromiseCapability(%Promise%). diff --git a/Userland/Libraries/LibJS/Runtime/FunctionConstructor.cpp b/Userland/Libraries/LibJS/Runtime/FunctionConstructor.cpp index ba091e1723..602de95cbd 100644 --- a/Userland/Libraries/LibJS/Runtime/FunctionConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/FunctionConstructor.cpp @@ -87,9 +87,7 @@ ThrowCompletionOr FunctionConstructor::construct(FunctionObject& new_ta } VM::InterpreterExecutionScope scope(*interpreter); - auto result = function->execute(*interpreter, global_object()); - if (auto* exception = vm.exception()) - return throw_completion(exception->value()); + auto result = TRY(function->execute(*interpreter, global_object())).release_value(); VERIFY(result.is_object() && is(result.as_object())); return &result.as_object(); } diff --git a/Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp b/Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp index 9f8c7b4354..2022265c21 100644 --- a/Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp +++ b/Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Linus Groh + * Copyright (c) 2021-2022, Linus Groh * * SPDX-License-Identifier: BSD-2-Clause */ @@ -117,13 +117,7 @@ ThrowCompletionOr perform_shadow_realm_eval(GlobalObject& global_object, // TODO: Optionally use bytecode interpreter? // FIXME: We need to use evaluate_statements() here because Program::execute() calls global_declaration_instantiation() when it shouldn't // a. Set result to the result of evaluating body. - auto result_value = program->evaluate_statements(vm.interpreter(), eval_realm.global_object()); - if (auto* exception = vm.exception()) - result = throw_completion(exception->value()); - else if (!result_value.is_empty()) - result = normal_completion(result_value); - else - result = Completion {}; // Normal completion with no value + result = program->evaluate_statements(vm.interpreter(), eval_realm.global_object()); } // 21. If result.[[Type]] is normal and result.[[Value]] is empty, then diff --git a/Userland/Libraries/LibJS/Runtime/VM.cpp b/Userland/Libraries/LibJS/Runtime/VM.cpp index c0705dc61e..1416853766 100644 --- a/Userland/Libraries/LibJS/Runtime/VM.cpp +++ b/Userland/Libraries/LibJS/Runtime/VM.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2020-2021, Andreas Kling - * Copyright (c) 2020-2021, Linus Groh + * Copyright (c) 2020-2022, Linus Groh * Copyright (c) 2021, David Tuin * * SPDX-License-Identifier: BSD-2-Clause @@ -160,10 +160,7 @@ ThrowCompletionOr VM::named_evaluation_if_anonymous_function(GlobalObject } } - auto value = expression.execute(interpreter(), global_object); - if (auto* thrown_exception = exception()) - return JS::throw_completion(thrown_exception->value()); - return value; + return TRY(expression.execute(interpreter(), global_object)).release_value(); } // 13.15.5.2 Runtime Semantics: DestructuringAssignmentEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-destructuringassignmentevaluation @@ -244,9 +241,6 @@ ThrowCompletionOr VM::property_binding_initialization(BindingPattern const VERIFY_NOT_REACHED(); } - if (auto* thrown_exception = exception()) - return JS::throw_completion(thrown_exception->value()); - auto* rest_object = Object::create(global_object, global_object.object_prototype()); VERIFY(rest_object); @@ -257,25 +251,15 @@ ThrowCompletionOr VM::property_binding_initialization(BindingPattern const return assignment_target.initialize_referenced_binding(global_object, rest_object); } - PropertyKey name; - - property.name.visit( - [&](Empty) { VERIFY_NOT_REACHED(); }, - [&](NonnullRefPtr const& identifier) { - name = identifier->string(); + auto name = TRY(property.name.visit( + [&](Empty) -> ThrowCompletionOr { VERIFY_NOT_REACHED(); }, + [&](NonnullRefPtr const& identifier) -> ThrowCompletionOr { + return identifier->string(); }, - [&](NonnullRefPtr const& expression) { - auto result = expression->execute(interpreter(), global_object); - if (exception()) - return; - auto name_or_error = result.to_property_key(global_object); - if (name_or_error.is_error()) - return; - name = name_or_error.release_value(); - }); - - if (auto* thrown_exception = exception()) - return JS::throw_completion(thrown_exception->value()); + [&](NonnullRefPtr const& expression) -> ThrowCompletionOr { + auto result = TRY(expression->execute(interpreter(), global_object)).release_value(); + return result.to_property_key(global_object); + })); seen_names.set(name); @@ -306,18 +290,12 @@ ThrowCompletionOr VM::property_binding_initialization(BindingPattern const return TRY(member_expression->to_reference(interpreter(), global_object)); })); - if (auto* thrown_exception = exception()) - return JS::throw_completion(thrown_exception->value()); - auto value_to_assign = TRY(object->get(name)); if (property.initializer && value_to_assign.is_undefined()) { if (auto* identifier_ptr = property.alias.get_pointer>()) value_to_assign = TRY(named_evaluation_if_anonymous_function(global_object, *property.initializer, (*identifier_ptr)->string())); else - value_to_assign = property.initializer->execute(interpreter(), global_object); - - if (auto* thrown_exception = exception()) - return JS::throw_completion(thrown_exception->value()); + value_to_assign = TRY(property.initializer->execute(interpreter(), global_object)).release_value(); } if (auto* binding_ptr = property.alias.get_pointer>()) { @@ -405,10 +383,7 @@ ThrowCompletionOr VM::iterator_binding_initialization(BindingPattern const if (auto* identifier_ptr = entry.alias.get_pointer>()) value = TRY(named_evaluation_if_anonymous_function(global_object, *entry.initializer, (*identifier_ptr)->string())); else - value = entry.initializer->execute(interpreter(), global_object); - - if (auto* thrown_exception = exception()) - return JS::throw_completion(thrown_exception->value()); + value = TRY(entry.initializer->execute(interpreter(), global_object)).release_value(); } if (auto* binding_ptr = entry.alias.get_pointer>()) {