|
@@ -238,55 +238,6 @@ ThrowCompletionOr<Value> VM::named_evaluation_if_anonymous_function(ASTNode cons
|
|
|
return execute_ast_node(expression);
|
|
|
}
|
|
|
|
|
|
-// 8.5.2 Runtime Semantics: BindingInitialization, https://tc39.es/ecma262/#sec-runtime-semantics-bindinginitialization
|
|
|
-ThrowCompletionOr<void> VM::binding_initialization(DeprecatedFlyString const& target, Value value, Environment* environment)
|
|
|
-{
|
|
|
- // 1. Let name be StringValue of Identifier.
|
|
|
- // 2. Return ? InitializeBoundName(name, value, environment).
|
|
|
- return initialize_bound_name(*this, target, value, environment);
|
|
|
-}
|
|
|
-
|
|
|
-// 8.5.2 Runtime Semantics: BindingInitialization, https://tc39.es/ecma262/#sec-runtime-semantics-bindinginitialization
|
|
|
-ThrowCompletionOr<void> VM::binding_initialization(NonnullRefPtr<BindingPattern const> const& target, Value value, Environment* environment)
|
|
|
-{
|
|
|
- auto& vm = *this;
|
|
|
-
|
|
|
- // BindingPattern : ObjectBindingPattern
|
|
|
- if (target->kind == BindingPattern::Kind::Object) {
|
|
|
- // 1. Perform ? RequireObjectCoercible(value).
|
|
|
- TRY(require_object_coercible(vm, value));
|
|
|
-
|
|
|
- // 2. Return ? BindingInitialization of ObjectBindingPattern with arguments value and environment.
|
|
|
-
|
|
|
- // BindingInitialization of ObjectBindingPattern
|
|
|
- // 1. Perform ? PropertyBindingInitialization of BindingPropertyList with arguments value and environment.
|
|
|
- TRY(property_binding_initialization(*target, value, environment));
|
|
|
-
|
|
|
- // 2. Return unused.
|
|
|
- return {};
|
|
|
- }
|
|
|
- // BindingPattern : ArrayBindingPattern
|
|
|
- else {
|
|
|
- // 1. Let iteratorRecord be ? GetIterator(value, sync).
|
|
|
- auto iterator_record = TRY(get_iterator(vm, value, IteratorHint::Sync));
|
|
|
-
|
|
|
- // 2. Let result be Completion(IteratorBindingInitialization of ArrayBindingPattern with arguments iteratorRecord and environment).
|
|
|
- auto result = iterator_binding_initialization(*target, iterator_record, environment);
|
|
|
-
|
|
|
- // 3. If iteratorRecord.[[Done]] is false, return ? IteratorClose(iteratorRecord, result).
|
|
|
- if (!iterator_record->done) {
|
|
|
- // iterator_close() always returns a Completion, which ThrowCompletionOr will interpret as a throw
|
|
|
- // completion. So only return the result of iterator_close() if it is indeed a throw completion.
|
|
|
- auto completion = result.is_throw_completion() ? result.release_error() : normal_completion({});
|
|
|
- if (completion = iterator_close(vm, iterator_record, move(completion)); completion.is_error())
|
|
|
- return completion.release_error();
|
|
|
- }
|
|
|
-
|
|
|
- // 4. Return ? result.
|
|
|
- return result;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
ThrowCompletionOr<Value> VM::execute_ast_node(ASTNode const& node)
|
|
|
{
|
|
|
// FIXME: This function should be gone once we will emit bytecode for everything before executing instructions.
|
|
@@ -309,198 +260,6 @@ ThrowCompletionOr<Value> VM::execute_ast_node(ASTNode const& node)
|
|
|
return result_or_error.return_register_value;
|
|
|
}
|
|
|
|
|
|
-// 13.15.5.3 Runtime Semantics: PropertyDestructuringAssignmentEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-propertydestructuringassignmentevaluation
|
|
|
-// 14.3.3.1 Runtime Semantics: PropertyBindingInitialization, https://tc39.es/ecma262/#sec-destructuring-binding-patterns-runtime-semantics-propertybindinginitialization
|
|
|
-ThrowCompletionOr<void> VM::property_binding_initialization(BindingPattern const& binding, Value value, Environment* environment)
|
|
|
-{
|
|
|
- auto& vm = *this;
|
|
|
- auto& realm = *vm.current_realm();
|
|
|
-
|
|
|
- auto object = TRY(value.to_object(vm));
|
|
|
-
|
|
|
- HashTable<PropertyKey> seen_names;
|
|
|
- for (auto& property : binding.entries) {
|
|
|
-
|
|
|
- VERIFY(!property.is_elision());
|
|
|
-
|
|
|
- if (property.is_rest) {
|
|
|
- Reference assignment_target;
|
|
|
- if (auto identifier_ptr = property.name.get_pointer<NonnullRefPtr<Identifier const>>()) {
|
|
|
- assignment_target = TRY(resolve_binding((*identifier_ptr)->string(), environment));
|
|
|
- } else {
|
|
|
- VERIFY_NOT_REACHED();
|
|
|
- }
|
|
|
-
|
|
|
- auto rest_object = Object::create(realm, realm.intrinsics().object_prototype());
|
|
|
- VERIFY(rest_object);
|
|
|
-
|
|
|
- TRY(rest_object->copy_data_properties(vm, object, seen_names));
|
|
|
- if (!environment)
|
|
|
- return assignment_target.put_value(vm, rest_object);
|
|
|
- else
|
|
|
- return assignment_target.initialize_referenced_binding(vm, rest_object);
|
|
|
- }
|
|
|
-
|
|
|
- auto name = TRY(property.name.visit(
|
|
|
- [&](Empty) -> ThrowCompletionOr<PropertyKey> { VERIFY_NOT_REACHED(); },
|
|
|
- [&](NonnullRefPtr<Identifier const> const& identifier) -> ThrowCompletionOr<PropertyKey> {
|
|
|
- return identifier->string();
|
|
|
- },
|
|
|
- [&](NonnullRefPtr<Expression const> const& expression) -> ThrowCompletionOr<PropertyKey> {
|
|
|
- auto result = TRY(execute_ast_node(*expression));
|
|
|
- return result.to_property_key(vm);
|
|
|
- }));
|
|
|
-
|
|
|
- seen_names.set(name);
|
|
|
-
|
|
|
- if (property.name.has<NonnullRefPtr<Identifier const>>() && property.alias.has<Empty>()) {
|
|
|
- // FIXME: this branch and not taking this have a lot in common we might want to unify it more (like it was before).
|
|
|
- auto& identifier = *property.name.get<NonnullRefPtr<Identifier const>>();
|
|
|
- auto reference = TRY(resolve_binding(identifier.string(), environment));
|
|
|
-
|
|
|
- auto value_to_assign = TRY(object->get(name));
|
|
|
- if (property.initializer && value_to_assign.is_undefined()) {
|
|
|
- value_to_assign = TRY(named_evaluation_if_anonymous_function(*property.initializer, identifier.string()));
|
|
|
- }
|
|
|
-
|
|
|
- if (!environment)
|
|
|
- TRY(reference.put_value(vm, value_to_assign));
|
|
|
- else
|
|
|
- TRY(reference.initialize_referenced_binding(vm, value_to_assign));
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- auto reference_to_assign_to = TRY(property.alias.visit(
|
|
|
- [&](Empty) -> ThrowCompletionOr<Optional<Reference>> { return Optional<Reference> {}; },
|
|
|
- [&](NonnullRefPtr<Identifier const> const& identifier) -> ThrowCompletionOr<Optional<Reference>> {
|
|
|
- return TRY(resolve_binding(identifier->string(), environment));
|
|
|
- },
|
|
|
- [&](NonnullRefPtr<BindingPattern const> const&) -> ThrowCompletionOr<Optional<Reference>> { return Optional<Reference> {}; },
|
|
|
- [&](NonnullRefPtr<MemberExpression const> const&) -> ThrowCompletionOr<Optional<Reference>> {
|
|
|
- VERIFY_NOT_REACHED();
|
|
|
- }));
|
|
|
-
|
|
|
- auto value_to_assign = TRY(object->get(name));
|
|
|
- if (property.initializer && value_to_assign.is_undefined()) {
|
|
|
- if (auto* identifier_ptr = property.alias.get_pointer<NonnullRefPtr<Identifier const>>())
|
|
|
- value_to_assign = TRY(named_evaluation_if_anonymous_function(*property.initializer, (*identifier_ptr)->string()));
|
|
|
- else
|
|
|
- value_to_assign = TRY(execute_ast_node(*property.initializer));
|
|
|
- }
|
|
|
-
|
|
|
- if (auto* binding_ptr = property.alias.get_pointer<NonnullRefPtr<BindingPattern const>>()) {
|
|
|
- TRY(binding_initialization(*binding_ptr, value_to_assign, environment));
|
|
|
- } else {
|
|
|
- VERIFY(reference_to_assign_to.has_value());
|
|
|
- if (!environment)
|
|
|
- TRY(reference_to_assign_to->put_value(vm, value_to_assign));
|
|
|
- else
|
|
|
- TRY(reference_to_assign_to->initialize_referenced_binding(vm, value_to_assign));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return {};
|
|
|
-}
|
|
|
-
|
|
|
-// 13.15.5.5 Runtime Semantics: IteratorDestructuringAssignmentEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-iteratordestructuringassignmentevaluation
|
|
|
-// 8.5.3 Runtime Semantics: IteratorBindingInitialization, https://tc39.es/ecma262/#sec-runtime-semantics-iteratorbindinginitialization
|
|
|
-ThrowCompletionOr<void> VM::iterator_binding_initialization(BindingPattern const& binding, IteratorRecord& iterator_record, Environment* environment)
|
|
|
-{
|
|
|
- auto& vm = *this;
|
|
|
- auto& realm = *vm.current_realm();
|
|
|
-
|
|
|
- // FIXME: this method is nearly identical to destructuring assignment!
|
|
|
- for (size_t i = 0; i < binding.entries.size(); i++) {
|
|
|
- auto& entry = binding.entries[i];
|
|
|
- Value value;
|
|
|
-
|
|
|
- auto assignment_target = TRY(entry.alias.visit(
|
|
|
- [&](Empty) -> ThrowCompletionOr<Optional<Reference>> { return Optional<Reference> {}; },
|
|
|
- [&](NonnullRefPtr<Identifier const> const& identifier) -> ThrowCompletionOr<Optional<Reference>> {
|
|
|
- return TRY(resolve_binding(identifier->string(), environment));
|
|
|
- },
|
|
|
- [&](NonnullRefPtr<BindingPattern const> const&) -> ThrowCompletionOr<Optional<Reference>> { return Optional<Reference> {}; },
|
|
|
- [&](NonnullRefPtr<MemberExpression const> const&) -> ThrowCompletionOr<Optional<Reference>> {
|
|
|
- VERIFY_NOT_REACHED();
|
|
|
- }));
|
|
|
-
|
|
|
- // BindingRestElement : ... BindingIdentifier
|
|
|
- // BindingRestElement : ... BindingPattern
|
|
|
- if (entry.is_rest) {
|
|
|
- VERIFY(i == binding.entries.size() - 1);
|
|
|
-
|
|
|
- // 2. Let A be ! ArrayCreate(0).
|
|
|
- auto array = MUST(Array::create(realm, 0));
|
|
|
-
|
|
|
- // 3. Let n be 0.
|
|
|
- // 4. Repeat,
|
|
|
- while (true) {
|
|
|
- // a. Let next be DONE.
|
|
|
- Optional<Value> next;
|
|
|
-
|
|
|
- // b. If iteratorRecord.[[Done]] is false, then
|
|
|
- if (!iterator_record.done) {
|
|
|
- // i. Set next to ? IteratorStepValue(iteratorRecord).
|
|
|
- next = TRY(iterator_step_value(vm, iterator_record));
|
|
|
- }
|
|
|
-
|
|
|
- // c. If next is DONE, then
|
|
|
- if (!next.has_value()) {
|
|
|
- // NOTE: Step i. and ii. are handled below.
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- // d. Perform ! CreateDataPropertyOrThrow(A, ! ToString(𝔽(n)), next).
|
|
|
- array->indexed_properties().append(next.release_value());
|
|
|
-
|
|
|
- // e. Set n to n + 1.
|
|
|
- }
|
|
|
-
|
|
|
- value = array;
|
|
|
- }
|
|
|
- // SingleNameBinding : BindingIdentifier Initializer[opt]
|
|
|
- // BindingElement : BindingPattern Initializer[opt]
|
|
|
- else {
|
|
|
- // 1. Let v be undefined.
|
|
|
- value = js_undefined();
|
|
|
-
|
|
|
- // 2. If iteratorRecord.[[Done]] is false, then
|
|
|
- if (!iterator_record.done) {
|
|
|
- // a. Let next be ? IteratorStepValue(iteratorRecord).
|
|
|
- auto next = TRY(iterator_step_value(vm, iterator_record));
|
|
|
-
|
|
|
- // b. If next is not DONE, then
|
|
|
- if (next.has_value()) {
|
|
|
- // i. Set v to next.
|
|
|
- value = next.release_value();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // NOTE: Step 3. and 4. are handled below.
|
|
|
- }
|
|
|
-
|
|
|
- if (value.is_undefined() && entry.initializer) {
|
|
|
- VERIFY(!entry.is_rest);
|
|
|
- if (auto* identifier_ptr = entry.alias.get_pointer<NonnullRefPtr<Identifier const>>())
|
|
|
- value = TRY(named_evaluation_if_anonymous_function(*entry.initializer, (*identifier_ptr)->string()));
|
|
|
- else
|
|
|
- value = TRY(execute_ast_node(*entry.initializer));
|
|
|
- }
|
|
|
-
|
|
|
- if (auto* binding_ptr = entry.alias.get_pointer<NonnullRefPtr<BindingPattern const>>()) {
|
|
|
- TRY(binding_initialization(*binding_ptr, value, environment));
|
|
|
- } else if (!entry.alias.has<Empty>()) {
|
|
|
- VERIFY(assignment_target.has_value());
|
|
|
- if (!environment)
|
|
|
- TRY(assignment_target->put_value(vm, value));
|
|
|
- else
|
|
|
- TRY(assignment_target->initialize_referenced_binding(vm, value));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return {};
|
|
|
-}
|
|
|
-
|
|
|
// 9.1.2.1 GetIdentifierReference ( env, name, strict ), https://tc39.es/ecma262/#sec-getidentifierreference
|
|
|
ThrowCompletionOr<Reference> VM::get_identifier_reference(Environment* environment, DeprecatedFlyString name, bool strict, size_t hops)
|
|
|
{
|