summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibJS/Runtime/LexicalEnvironment.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Userland/Libraries/LibJS/Runtime/LexicalEnvironment.cpp')
-rw-r--r--Userland/Libraries/LibJS/Runtime/LexicalEnvironment.cpp134
1 files changed, 134 insertions, 0 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/LexicalEnvironment.cpp b/Userland/Libraries/LibJS/Runtime/LexicalEnvironment.cpp
new file mode 100644
index 0000000000..2275b6402b
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/LexicalEnvironment.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <LibJS/Interpreter.h>
+#include <LibJS/Runtime/Error.h>
+#include <LibJS/Runtime/Function.h>
+#include <LibJS/Runtime/GlobalObject.h>
+#include <LibJS/Runtime/LexicalEnvironment.h>
+#include <LibJS/Runtime/Value.h>
+
+namespace JS {
+
+LexicalEnvironment::LexicalEnvironment()
+ : ScopeObject(nullptr)
+{
+}
+
+LexicalEnvironment::LexicalEnvironment(EnvironmentRecordType environment_record_type)
+ : ScopeObject(nullptr)
+ , m_environment_record_type(environment_record_type)
+{
+}
+
+LexicalEnvironment::LexicalEnvironment(HashMap<FlyString, Variable> variables, ScopeObject* parent_scope)
+ : ScopeObject(parent_scope)
+ , m_variables(move(variables))
+{
+}
+
+LexicalEnvironment::LexicalEnvironment(HashMap<FlyString, Variable> 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)
+{
+ Cell::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<Variable> 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()
+{
+ ASSERT(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;
+ }
+ ASSERT_NOT_REACHED();
+}
+
+Value LexicalEnvironment::get_this_binding(GlobalObject& global_object) const
+{
+ ASSERT(has_this_binding());
+ if (this_binding_status() == ThisBindingStatus::Uninitialized) {
+ vm().throw_exception<ReferenceError>(global_object, ErrorType::ThisHasNotBeenInitialized);
+ return {};
+ }
+ return m_this_value;
+}
+
+void LexicalEnvironment::bind_this_value(GlobalObject& global_object, Value this_value)
+{
+ ASSERT(has_this_binding());
+ if (m_this_binding_status == ThisBindingStatus::Initialized) {
+ vm().throw_exception<ReferenceError>(global_object, ErrorType::ThisIsAlreadyInitialized);
+ return;
+ }
+ m_this_value = this_value;
+ m_this_binding_status = ThisBindingStatus::Initialized;
+}
+
+}