#ifndef PORYGONLANG_TABLESCRIPTTYPE_HPP #define PORYGONLANG_TABLESCRIPTTYPE_HPP #include #include #include #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>*; using KeyValueType = std::pair, shared_ptr>; bool _isContentAware = false; TableType _tableType; std::variant< shared_ptr, ContentTypes, KeyValueType > _valueType, _contentTypes, _keyValueType; [[nodiscard]] inline shared_ptr GetValueType() const{ return std::get>(_valueType); } [[nodiscard]] inline KeyValueType GetKeyValueTypes() const{ return std::get(_keyValueType); } public: explicit TableScriptType() : ScriptType(TypeClass::Table), _tableType(TableType::Unknown) {} explicit TableScriptType(shared_ptr valueType) : ScriptType(TypeClass::Table), _tableType(TableType::Numerical), _valueType(std::move(valueType)) {} explicit TableScriptType(unordered_map>* contentTypes) : ScriptType(TypeClass::Table), _tableType(TableType::StringKeyed), _contentTypes(contentTypes), _isContentAware(true) {} explicit TableScriptType(std::pair, shared_ptr> 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 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 GetIndexedType(shared_ptr indexer) const override { if (_tableType == TableType::Unknown) return ScriptType::AnyType; else if (_tableType == TableType::StringKeyed){ auto stringType = dynamic_pointer_cast(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 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); } [[nodiscard]] bool CanSetIndexValue(shared_ptr indexer, shared_ptr 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 val) const override { switch (_tableType){ case StringKeyed: return true; case Unknown: return true; default: break; } return false; } void SetIndexValue(shared_ptr indexer, shared_ptr val) const override { if (_tableType == TableType::StringKeyed){ auto s = dynamic_pointer_cast(indexer); if (s->IsKnownAtBind()){ auto key = s->GetHashValue(); GetContentTypes()->insert({key, val}); } } else if (_tableType == TableType::Unknown){ auto t = const_cast(this); if (indexer->GetClass() == TypeClass::Number){ t->_tableType = TableType ::Numerical; t->_valueType = val; } } } void SetIndexValue(Utilities::HashedString indexer, shared_ptr val) const override { if (_tableType == TableType::StringKeyed){ GetContentTypes()->insert({indexer, val}); } else if (_tableType == TableType::Unknown){ auto t = const_cast(this); t->_tableType = TableType ::StringKeyed; t->_isContentAware = true; t->_contentTypes = new unordered_map>{ {indexer, val} }; } } }; } #include "ScriptType.hpp" #endif //PORYGONLANG_TABLESCRIPTTYPE_HPP