2019-06-12 13:19:28 +00:00
|
|
|
|
|
|
|
#ifndef PORYGONLANG_TABLESCRIPTTYPE_HPP
|
|
|
|
#define PORYGONLANG_TABLESCRIPTTYPE_HPP
|
|
|
|
#include <unordered_map>
|
2019-09-15 11:08:11 +00:00
|
|
|
#include <utility>
|
2019-07-28 10:58:38 +00:00
|
|
|
#include "../Binder/BoundVariables/BoundVariable.hpp"
|
2019-09-15 11:08:11 +00:00
|
|
|
#include "../Exception.hpp"
|
2019-06-12 13:19:28 +00:00
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
namespace Porygon{
|
2019-09-15 11:08:11 +00:00
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
class TableScriptType : public ScriptType{
|
2019-09-15 11:08:11 +00:00
|
|
|
enum TableType{
|
|
|
|
Unknown,
|
|
|
|
Numerical,
|
|
|
|
StringKeyed,
|
|
|
|
Dictionary
|
|
|
|
};
|
|
|
|
|
|
|
|
bool _isContentAware;
|
|
|
|
TableType _tableType;
|
2019-06-12 13:19:28 +00:00
|
|
|
|
2019-09-15 11:08:11 +00:00
|
|
|
union{
|
|
|
|
shared_ptr<const ScriptType> _valueType; // numerical
|
|
|
|
unordered_map<Utilities::HashedString, shared_ptr<const ScriptType>>* _contentTypes = nullptr; // string keyed
|
|
|
|
std::pair<shared_ptr<const ScriptType>, shared_ptr<const ScriptType>> _keyValueType; // dictionary
|
|
|
|
};
|
|
|
|
|
|
|
|
public:
|
2019-09-01 18:07:09 +00:00
|
|
|
explicit TableScriptType()
|
2019-09-15 11:08:11 +00:00
|
|
|
: ScriptType(TypeClass::Table), _tableType(TableType::Unknown) {}
|
2019-09-01 18:07:09 +00:00
|
|
|
|
2019-09-15 11:08:11 +00:00
|
|
|
explicit TableScriptType(shared_ptr<const ScriptType> valueType)
|
|
|
|
: ScriptType(TypeClass::Table), _tableType(TableType::Numerical), _valueType(std::move(valueType)) {}
|
2019-09-01 18:07:09 +00:00
|
|
|
|
2019-09-15 11:08:11 +00:00
|
|
|
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 _contentTypes;
|
2019-06-12 13:19:28 +00:00
|
|
|
}
|
|
|
|
|
2019-09-15 11:08:11 +00:00
|
|
|
[[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.");
|
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
}
|
2019-06-12 13:19:28 +00:00
|
|
|
|
2019-09-15 11:08:11 +00:00
|
|
|
[[nodiscard]] bool IsCountable() const override {
|
2019-06-17 16:35:12 +00:00
|
|
|
return true;
|
|
|
|
}
|
2019-06-17 13:45:33 +00:00
|
|
|
|
2019-09-15 11:08:11 +00:00
|
|
|
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 = _keyValueType.first;
|
|
|
|
return indexer->CastableTo(keyType, false) != CastResult ::InvalidCast;
|
2019-06-17 16:35:12 +00:00
|
|
|
}
|
2019-06-12 13:19:28 +00:00
|
|
|
}
|
|
|
|
|
2019-09-15 11:08:11 +00:00
|
|
|
[[nodiscard]] bool CanBeIndexedWithIdentifier(uint32_t hash) const override {
|
|
|
|
if (_tableType != TableType::StringKeyed)
|
|
|
|
return false;
|
|
|
|
return _isContentAware;
|
2019-06-17 16:35:12 +00:00
|
|
|
}
|
2019-06-17 13:45:33 +00:00
|
|
|
|
2019-09-15 11:08:11 +00:00
|
|
|
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 _contentTypes->at(h);
|
|
|
|
}
|
|
|
|
return ScriptType::AnyType;
|
|
|
|
}
|
|
|
|
else if (_tableType == TableType::Numerical){
|
|
|
|
return _valueType;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
return _keyValueType.second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]] shared_ptr<const ScriptType> GetIndexedType(uint32_t hash) const override {
|
|
|
|
auto lookup = Utilities::HashedString::CreateLookup(hash);
|
|
|
|
return _contentTypes->at(lookup);
|
|
|
|
}
|
|
|
|
|
|
|
|
unordered_map<Utilities::HashedString, shared_ptr<const ScriptType>>* GetContentTypes() const{
|
|
|
|
return _contentTypes;
|
2019-06-17 16:35:12 +00:00
|
|
|
}
|
2019-09-01 18:07:09 +00:00
|
|
|
|
|
|
|
[[nodiscard]]
|
2019-09-15 11:08:11 +00:00
|
|
|
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(_valueType, false) != CastResult ::InvalidCast;
|
|
|
|
case StringKeyed:
|
|
|
|
return indexer->GetClass() == TypeClass ::String;
|
|
|
|
case Dictionary:
|
|
|
|
return indexer->CastableTo(_keyValueType.first, false) != CastResult ::InvalidCast &&
|
|
|
|
val->CastableTo(_keyValueType.second, false) != CastResult ::InvalidCast;
|
|
|
|
}
|
2019-09-01 18:07:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]]
|
2019-09-15 11:08:11 +00:00
|
|
|
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;
|
2019-09-01 18:07:09 +00:00
|
|
|
}
|
2019-09-12 16:19:06 +00:00
|
|
|
|
2019-09-15 11:08:11 +00:00
|
|
|
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();
|
|
|
|
_contentTypes->insert({key, val});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetIndexValue(Utilities::HashedString indexer, shared_ptr<const ScriptType> val) const override {
|
|
|
|
if (_tableType == TableType::StringKeyed){
|
|
|
|
_contentTypes->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}
|
|
|
|
};
|
|
|
|
}
|
2019-09-12 16:19:06 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
};
|
|
|
|
}
|
2019-06-12 13:19:28 +00:00
|
|
|
|
|
|
|
#include "ScriptType.hpp"
|
|
|
|
|
|
|
|
#endif //PORYGONLANG_TABLESCRIPTTYPE_HPP
|