mirror of
https://github.com/RGBCube/serenity
synced 2025-05-28 15:55:06 +00:00

This patch adds FunctionEnvironmentRecord as a subclass of the existing DeclarativeEnvironmentRecord. Things that are specific to function environment records move into there, simplifying the base. Most of the abstract operations related to function environment records are rewritten to match the spec exactly. I also had to implement GetThisEnvironment() and GetSuperConstructor() to keep tests working after the changes, so that's nice as well. :^)
97 lines
3 KiB
C++
97 lines
3 KiB
C++
/*
|
|
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/FlyString.h>
|
|
#include <AK/HashMap.h>
|
|
#include <AK/String.h>
|
|
#include <AK/Vector.h>
|
|
#include <AK/Weakable.h>
|
|
#include <LibJS/AST.h>
|
|
#include <LibJS/Forward.h>
|
|
#include <LibJS/Heap/DeferGC.h>
|
|
#include <LibJS/Heap/Heap.h>
|
|
#include <LibJS/Runtime/DeclarativeEnvironmentRecord.h>
|
|
#include <LibJS/Runtime/ErrorTypes.h>
|
|
#include <LibJS/Runtime/Exception.h>
|
|
#include <LibJS/Runtime/MarkedValueList.h>
|
|
#include <LibJS/Runtime/VM.h>
|
|
#include <LibJS/Runtime/Value.h>
|
|
|
|
namespace JS {
|
|
|
|
struct ExecutingASTNodeChain {
|
|
ExecutingASTNodeChain* previous { nullptr };
|
|
const ASTNode& node;
|
|
};
|
|
|
|
class Interpreter : public Weakable<Interpreter> {
|
|
public:
|
|
template<typename GlobalObjectType, typename... Args>
|
|
static NonnullOwnPtr<Interpreter> create(VM& vm, Args&&... args)
|
|
{
|
|
DeferGC defer_gc(vm.heap());
|
|
auto interpreter = adopt_own(*new Interpreter(vm));
|
|
VM::InterpreterExecutionScope scope(*interpreter);
|
|
interpreter->m_global_object = make_handle(static_cast<Object*>(interpreter->heap().allocate_without_global_object<GlobalObjectType>(forward<Args>(args)...)));
|
|
static_cast<GlobalObjectType*>(interpreter->m_global_object.cell())->initialize_global_object();
|
|
return interpreter;
|
|
}
|
|
|
|
static NonnullOwnPtr<Interpreter> create_with_existing_global_object(GlobalObject&);
|
|
|
|
~Interpreter();
|
|
|
|
void run(GlobalObject&, const Program&);
|
|
|
|
GlobalObject& global_object();
|
|
const GlobalObject& global_object() const;
|
|
|
|
ALWAYS_INLINE VM& vm() { return *m_vm; }
|
|
ALWAYS_INLINE const VM& vm() const { return *m_vm; }
|
|
ALWAYS_INLINE Heap& heap() { return vm().heap(); }
|
|
ALWAYS_INLINE Exception* exception() { return vm().exception(); }
|
|
|
|
EnvironmentRecord* current_environment_record() { return vm().current_environment_record(); }
|
|
|
|
FunctionEnvironmentRecord* current_function_environment_record();
|
|
|
|
void enter_scope(const ScopeNode&, ScopeType, GlobalObject&);
|
|
void exit_scope(const ScopeNode&);
|
|
|
|
void push_ast_node(ExecutingASTNodeChain& chain_node)
|
|
{
|
|
chain_node.previous = m_ast_node_chain;
|
|
m_ast_node_chain = &chain_node;
|
|
}
|
|
|
|
void pop_ast_node()
|
|
{
|
|
VERIFY(m_ast_node_chain);
|
|
m_ast_node_chain = m_ast_node_chain->previous;
|
|
}
|
|
|
|
const ASTNode* current_node() const { return m_ast_node_chain ? &m_ast_node_chain->node : nullptr; }
|
|
ExecutingASTNodeChain* executing_ast_node_chain() { return m_ast_node_chain; }
|
|
const ExecutingASTNodeChain* executing_ast_node_chain() const { return m_ast_node_chain; }
|
|
|
|
Value execute_statement(GlobalObject&, const Statement&, ScopeType = ScopeType::Block);
|
|
|
|
private:
|
|
explicit Interpreter(VM&);
|
|
|
|
void push_scope(ScopeFrame frame);
|
|
|
|
Vector<ScopeFrame> m_scope_stack;
|
|
ExecutingASTNodeChain* m_ast_node_chain { nullptr };
|
|
|
|
NonnullRefPtr<VM> m_vm;
|
|
|
|
Handle<Object> m_global_object;
|
|
};
|
|
|
|
}
|