197 lines
7.4 KiB
C++
197 lines
7.4 KiB
C++
|
|
#ifndef PORYGONLANG_TABLESCRIPTTYPE_HPP
|
|
#define PORYGONLANG_TABLESCRIPTTYPE_HPP
|
|
#include <unordered_map>
|
|
#include <utility>
|
|
#include <variant>
|
|
#include "../Binder/BoundVariables/BoundVariable.hpp"
|
|
#include "../Exception.hpp"
|
|
|
|
namespace Porygon{
|
|
|
|
class TableScriptType : public ScriptType{
|
|
public:
|
|
enum TableType{
|
|
Unknown,
|
|
Numerical,
|
|
StringKeyed,
|
|
Dictionary
|
|
};
|
|
private:
|
|
using ContentTypes = unordered_map<Utilities::HashedString, shared_ptr<const ScriptType>>*;
|
|
using KeyValueType = std::pair<shared_ptr<const ScriptType>, shared_ptr<const ScriptType>>;
|
|
|
|
bool _isContentAware = false;
|
|
TableType _tableType;
|
|
|
|
std::variant<
|
|
shared_ptr<const ScriptType>,
|
|
ContentTypes,
|
|
KeyValueType
|
|
> _valueType, _contentTypes, _keyValueType;
|
|
|
|
[[nodiscard]] inline shared_ptr<const ScriptType> GetValueType() const{
|
|
return std::get<shared_ptr<const ScriptType>>(_valueType);
|
|
}
|
|
|
|
[[nodiscard]] inline KeyValueType GetKeyValueTypes() const{
|
|
return std::get<KeyValueType>(_keyValueType);
|
|
}
|
|
|
|
public:
|
|
explicit TableScriptType()
|
|
: ScriptType(TypeClass::Table), _tableType(TableType::Unknown) {}
|
|
|
|
explicit TableScriptType(shared_ptr<const ScriptType> valueType)
|
|
: ScriptType(TypeClass::Table), _tableType(TableType::Numerical), _valueType(std::move(valueType)) {}
|
|
|
|
explicit TableScriptType(unordered_map<Utilities::HashedString, shared_ptr<const ScriptType>>* contentTypes)
|
|
: ScriptType(TypeClass::Table), _tableType(TableType::StringKeyed), _contentTypes(contentTypes),
|
|
_isContentAware(true) {}
|
|
|
|
explicit TableScriptType(std::pair<shared_ptr<ScriptType>, shared_ptr<ScriptType>> kvType)
|
|
: ScriptType(TypeClass::Table), _tableType(TableType::Dictionary), _keyValueType(std::move(kvType)) {}
|
|
|
|
~TableScriptType() override {
|
|
if (_tableType == TableType::StringKeyed)
|
|
delete GetContentTypes();
|
|
}
|
|
|
|
[[nodiscard]] bool CanBeIterated() const final {
|
|
return true;
|
|
}
|
|
|
|
[[nodiscard]] shared_ptr<const ScriptType> GetIteratorKeyType() const override {
|
|
switch (_tableType){
|
|
case Unknown: return ScriptType::AnyType;
|
|
case Numerical: return NumericScriptType::AwareInt;
|
|
case StringKeyed: return StringScriptType::Dynamic;
|
|
case Dictionary: throw Exception("Not implemented.");
|
|
}
|
|
}
|
|
|
|
[[nodiscard]] bool IsCountable() const override {
|
|
return true;
|
|
}
|
|
|
|
bool CanBeIndexedWith(const ScriptType *indexer) const override {
|
|
if (_tableType == TableType::Unknown)
|
|
return true;
|
|
else if (_tableType == TableType::StringKeyed){
|
|
return indexer->GetClass() == TypeClass::String;
|
|
}
|
|
else if (_tableType == TableType::Numerical){
|
|
return indexer->GetClass() == TypeClass::Number;
|
|
}
|
|
else{
|
|
auto keyType = GetKeyValueTypes().first;
|
|
return indexer->CastableTo(keyType, false) != CastResult ::InvalidCast;
|
|
}
|
|
}
|
|
|
|
[[nodiscard]] bool CanBeIndexedWithIdentifier(uint32_t hash) const override {
|
|
if (_tableType != TableType::StringKeyed)
|
|
return false;
|
|
return _isContentAware;
|
|
}
|
|
|
|
[[nodiscard]] shared_ptr<const ScriptType> GetIndexedType(shared_ptr<const ScriptType> indexer) const override {
|
|
if (_tableType == TableType::Unknown)
|
|
return ScriptType::AnyType;
|
|
else if (_tableType == TableType::StringKeyed){
|
|
auto stringType = dynamic_pointer_cast<const StringScriptType>(indexer);
|
|
if (stringType->IsKnownAtBind() && _isContentAware){
|
|
auto h = stringType->GetHashValue();
|
|
return GetContentTypes()->at(h);
|
|
}
|
|
return ScriptType::AnyType;
|
|
}
|
|
else if (_tableType == TableType::Numerical){
|
|
return GetValueType();
|
|
}
|
|
else{
|
|
return GetKeyValueTypes().second;
|
|
}
|
|
}
|
|
|
|
[[nodiscard]] shared_ptr<const ScriptType> GetIndexedType(uint32_t hash) const override {
|
|
auto lookup = Utilities::HashedString::CreateLookup(hash);
|
|
if (GetContentTypes()->find(lookup) != GetContentTypes()->end()){
|
|
return GetContentTypes()->at(lookup);
|
|
}
|
|
else{
|
|
return ScriptType::AnyType;
|
|
}
|
|
}
|
|
|
|
[[nodiscard]] inline ContentTypes GetContentTypes() const{
|
|
return std::get<ContentTypes>(_contentTypes);
|
|
}
|
|
|
|
[[nodiscard]]
|
|
bool CanSetIndexValue(shared_ptr<const ScriptType> indexer, shared_ptr<const ScriptType> val) const override {
|
|
switch (_tableType){
|
|
|
|
case Unknown: return true;
|
|
case Numerical:
|
|
return indexer->GetClass() == TypeClass ::Number &&
|
|
val->CastableTo(GetValueType(), false) != CastResult ::InvalidCast;
|
|
case StringKeyed:
|
|
return indexer->GetClass() == TypeClass ::String;
|
|
case Dictionary:
|
|
return indexer->CastableTo(GetKeyValueTypes().first, false) != CastResult ::InvalidCast &&
|
|
val->CastableTo(GetKeyValueTypes().second, false) != CastResult ::InvalidCast;
|
|
}
|
|
}
|
|
|
|
[[nodiscard]]
|
|
bool CanSetIndexValue(Utilities::HashedString indexer, shared_ptr<const ScriptType> val) const override {
|
|
switch (_tableType){
|
|
case StringKeyed:
|
|
return true;
|
|
case Unknown:
|
|
return true;
|
|
default:
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void SetIndexValue(shared_ptr<const ScriptType> indexer, shared_ptr<const ScriptType> val) const override {
|
|
if (_tableType == TableType::StringKeyed){
|
|
auto s = dynamic_pointer_cast<const StringScriptType>(indexer);
|
|
if (s->IsKnownAtBind()){
|
|
auto key = s->GetHashValue();
|
|
GetContentTypes()->insert({key, val});
|
|
}
|
|
}
|
|
else if (_tableType == TableType::Unknown){
|
|
auto t = const_cast<TableScriptType*>(this);
|
|
if (indexer->GetClass() == TypeClass::Number){
|
|
t->_tableType = TableType ::Numerical;
|
|
t->_valueType = val;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SetIndexValue(Utilities::HashedString indexer, shared_ptr<const ScriptType> val) const override {
|
|
if (_tableType == TableType::StringKeyed){
|
|
GetContentTypes()->insert({indexer, val});
|
|
}
|
|
else if (_tableType == TableType::Unknown){
|
|
auto t = const_cast<TableScriptType*>(this);
|
|
t->_tableType = TableType ::StringKeyed;
|
|
t->_isContentAware = true;
|
|
t->_contentTypes = new unordered_map<Utilities::HashedString, shared_ptr<const ScriptType>>{
|
|
{indexer, val}
|
|
};
|
|
}
|
|
}
|
|
|
|
};
|
|
}
|
|
|
|
#include "ScriptType.hpp"
|
|
|
|
#endif //PORYGONLANG_TABLESCRIPTTYPE_HPP
|