#pragma once
#include "engine/engine.h"
#include "engine/identifiers.h"
#include "engine/symlevel/definitions.h"
#include "engine/terms.h"
#include "utils/iterators.h"
#include "utils/logger.h"
#include <memory>
#include <vector>
namespace Engine {
/// Each method table can be constructed for some type definition or term that instantiates type definition.
/// The method table is needed for virtual and interface method resolution (including dynamic "static" methods).
///
/// The table consists of two layers, so any entry could be referenced by two indexes or actual type + method index.
/// To perform a method reference resolution of form `(ref type, method name, signature)` we need to:
/// 1. Find a sub-table that corresponds to `ref type`;
/// 2. Find entry that corresponds to `method name; signature` (can require generic instantiation).
/// The entry found is resolution result.
///
/// The table is structured as an array of all entries, where each sub table is a view to the array,
/// so intersections are allowed.
/// This layout can help to abstract away an actual data needed in run time to perform dynamic call.
/// E.g. if VMT is structured as:
/// - flat array of methods
/// - mapping: interface type info -> offset in the flat array
/// so virtual methods could be referenced by one number, we can map our method table to this kind of layout easily.
///
/// A new table of class `A <: C & I & J` will look like as table for `C` with added interface sub tables from `I` and
/// `J`, where entries for overridden methods are patched. New methods would be added as new class sub table.
/// The value of that describe an entry in method table.
struct MethodTableEntry {
/// The method which is being referenced.
Identifier<Symlevel::MethodDefinition> method;
/// Declaring type, where method is actually declared. Additionally to type definition,
/// stores an generic variable parameterization.
Term genericContext;
/// Method number in sub table.
int methodNum;
/// Number of sub table.
int subTableNum;
/// idx in all entries array
int flatMethodNum;
};
class MethodSubTable;
/// @see description on top of current header.
class MethodTable {
struct SubTable {
Term genericContext;
int start;
int end;
};
public:
MethodTable() = default;
struct Entry {
/// The method which is being referenced.
Identifier<Symlevel::MethodDefinition> method;
/// Declaring type, where method is actually declared. Additionally to type definition,
/// stores an generic variable parameterization.
Term genericContext;
};
struct SubTableGenerator {
MethodTable const& table;
std::vector<SubTable> const& subtables;
int const disp;
int cursor;
std::optional<MethodSubTable> operator()();
};
using Range = Iterators::SimpleRange<SubTableGenerator>;
auto Entries()
{
struct EntryView {
MethodTable const& table;
auto begin() { return table.allEntries.begin(); }
auto end() { return table.allEntries.end(); }
};
return EntryView { *this };
};
void Globalize(Session& session);
Range Classes() const;
Range Interfaces() const;
int ClassCount() const;
int InterfaceCount() const;
int EntryCount() const;
struct Reference {
std::string_view name;
Term signature;
};
/// Resolve the reference passed in hierarchy, e.g.:
/// interfaces:
/// I: foo(0), bar(1), baz(2)
/// J <: I: qwe(0)
/// class Foo <: I & J {}
///
/// reference:
/// - J.foo will be resolved up to (I, 0)
/// - J.baz will be resolved up to (I, 2)
/// - J.qwe will be resolved up to (J, 0)
std::optional<MethodTableEntry> Resolve(Session& session, Reference const& reference) const;
void ResolveAll(Session& session, Reference const& reference, std::vector<MethodTableEntry>& buffer) const;
private:
friend class MethodSubTable;
friend class MethodTableManager;
MethodTable(
std::vector<Entry>&& allEntries, std::vector<SubTable>&& classTables, std::vector<SubTable>&& interfaceTables
);
std::vector<Entry> allEntries;
std::vector<SubTable> classTables;
std::vector<SubTable> interfaceTables;
};
/// Second layer of the table. Can query entries in this sub table and type that corresponds to
/// one of a super types of the owner of whole method table.
class MethodSubTable {
public:
struct EntryGenerator {
MethodSubTable const& st;
int cursor;
std::optional<MethodTableEntry> operator()();
};
using Range = Iterators::SimpleRange<EntryGenerator>;
int StartPos() const;
int EndPos() const;
int Size() const;
int Num() const;
Term DeclaringType() const;
Range Entries() const;
private:
friend class MethodTable::SubTableGenerator;
friend class MethodTableManager;
MethodSubTable(MethodTable const& table, Term declaringType, int start, int end, int num);
MethodTable const* table;
Term declaringType;
int start;
int end;
int num;
};
class MethodTableManager {
public:
static MethodTableManager& Of(Engine& engine);
static MethodTableManager& Of(Session& session);
static std::unique_ptr<MethodTableManager> NewInstance();
virtual ~MethodTableManager() = default;
/// Returns an method table for the given type definition.
virtual std::optional<std::shared_ptr<MethodTable>> GetMethodTable(
Session& session, Identifier<Symlevel::TypeDefinition> type
) = 0;
/// Returns an method table for the given type.
std::optional<std::shared_ptr<MethodTable>> GetMethodTable(Session& session, Term term);
protected:
std::optional<MethodTable> BuildTable(Session& session, Identifier<Symlevel::TypeDefinition> type);
MethodTable BaseTable();
};
namespace Log {
/// Logger for method table building and querying.
/// DEBUG - log method tables structure
/// INFO - log queries of method table
/// ERROR - log errors
extern Logging::Logger mt;
} // namespace Log
} // namespace Engine