/* * Copyright (c) 2024, Dan Klishch * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include "DiagnosticEngine.h" #include "Function.h" #include "Runtime/ObjectType.h" namespace JSSpecCompiler::Runtime { struct Slot { bool operator==(Slot const&) const = default; FlyString key; }; struct StringPropertyKey { bool operator==(StringPropertyKey const&) const = default; FlyString key; }; #define ENUMERATE_WELL_KNOWN_SYMBOLS(F) \ F(InstanceType, _instanceType) \ F(ToStringTag, toStringTag) enum class WellKnownSymbol { #define ID(enum_name, spec_name) enum_name, ENUMERATE_WELL_KNOWN_SYMBOLS(ID) #undef ID }; class PropertyKey : public Variant { public: using Variant::Variant; }; struct DataProperty { template bool is() const { return ::is(value); } template T* as() const { return verify_cast(value); } template Optional get_or_diagnose(Realm* realm, QualifiedName name, Location location) { if (!is()) { realm->diag().error(location, "{} must be a {}", name.to_string(), T::TYPE_NAME); realm->diag().note(this->location, "set to {} here", value->type_name()); return {}; } return verify_cast(value); } Cell* value; Location location; bool is_writable = true; bool is_enumerable = false; bool is_configurable = true; }; struct AccessorProperty { Optional getter; Optional setter; Location location; bool is_enumerable = false; bool is_configurable = true; }; class Property : public Variant { public: using Variant::Variant; Location location() const { return visit([&](auto const& value) { return value.location; }); } Optional get_data_property_or_diagnose(Realm* realm, QualifiedName name, Location location); }; class Object : public Runtime::Cell { public: static constexpr StringView TYPE_NAME = "object"sv; static Object* create(Realm* realm) { return realm->adopt_cell(new Object {}); } StringView type_name() const override { return TYPE_NAME; } auto& type() { return m_type; } auto& properties() { return m_properties; } bool has(PropertyKey const& key) const { return m_properties.contains(key); } Property& get(PropertyKey const& key) { return m_properties.get(key).value(); } void set(PropertyKey const& key, Property&& property) { auto insertion_result = m_properties.set(key, move(property)); VERIFY(insertion_result == HashSetResult::InsertedNewEntry); } protected: void do_dump(Printer& printer) const override; private: Object() = default; Optional m_type; HashMap m_properties; }; } template<> struct AK::Traits : public DefaultTraits { static unsigned hash(JSSpecCompiler::Runtime::PropertyKey const& key) { using namespace JSSpecCompiler::Runtime; return key.visit( [](Slot const& slot) { return pair_int_hash(1, slot.key.hash()); }, [](StringPropertyKey const& string_key) { return pair_int_hash(2, string_key.key.hash()); }, [](WellKnownSymbol const& symbol) { return pair_int_hash(3, to_underlying(symbol)); }); } };