/* * Copyright (c) 2020, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include namespace JS { LexicalEnvironment::LexicalEnvironment() : ScopeObject(nullptr) { } LexicalEnvironment::LexicalEnvironment(EnvironmentRecordType environment_record_type) : ScopeObject(nullptr) , m_environment_record_type(environment_record_type) { } LexicalEnvironment::LexicalEnvironment(HashMap variables, ScopeObject* parent_scope) : ScopeObject(parent_scope) , m_variables(move(variables)) { } LexicalEnvironment::LexicalEnvironment(HashMap variables, ScopeObject* parent_scope, EnvironmentRecordType environment_record_type) : ScopeObject(parent_scope) , m_environment_record_type(environment_record_type) , m_variables(move(variables)) { } LexicalEnvironment::~LexicalEnvironment() { } void LexicalEnvironment::visit_edges(Visitor& visitor) { Base::visit_edges(visitor); visitor.visit(m_this_value); visitor.visit(m_home_object); visitor.visit(m_new_target); visitor.visit(m_current_function); for (auto& it : m_variables) visitor.visit(it.value.value); } Optional LexicalEnvironment::get_from_scope(const FlyString& name) const { return m_variables.get(name); } void LexicalEnvironment::put_to_scope(const FlyString& name, Variable variable) { m_variables.set(name, variable); } bool LexicalEnvironment::has_super_binding() const { return m_environment_record_type == EnvironmentRecordType::Function && this_binding_status() != ThisBindingStatus::Lexical && m_home_object.is_object(); } Value LexicalEnvironment::get_super_base() { VERIFY(has_super_binding()); if (m_home_object.is_object()) return m_home_object.as_object().prototype(); return {}; } bool LexicalEnvironment::has_this_binding() const { // More like "is_capable_of_having_a_this_binding". switch (m_environment_record_type) { case EnvironmentRecordType::Declarative: case EnvironmentRecordType::Object: return false; case EnvironmentRecordType::Function: return this_binding_status() != ThisBindingStatus::Lexical; case EnvironmentRecordType::Module: return true; } VERIFY_NOT_REACHED(); } Value LexicalEnvironment::get_this_binding(GlobalObject& global_object) const { VERIFY(has_this_binding()); if (this_binding_status() == ThisBindingStatus::Uninitialized) { vm().throw_exception(global_object, ErrorType::ThisHasNotBeenInitialized); return {}; } return m_this_value; } void LexicalEnvironment::bind_this_value(GlobalObject& global_object, Value this_value) { VERIFY(has_this_binding()); if (m_this_binding_status == ThisBindingStatus::Initialized) { vm().throw_exception(global_object, ErrorType::ThisIsAlreadyInitialized); return; } m_this_value = this_value; m_this_binding_status = ThisBindingStatus::Initialized; } }