1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-28 15:55:06 +00:00
serenity/Userland/Libraries/LibJS/Interpreter.h
Andreas Kling aabd82d508 LibJS: Bring function environment records closer to the spec
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. :^)
2021-06-22 18:44:53 +02:00

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;
};
}