From 458274f370cef206fba167acff2192f4fdddbbeb Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sun, 15 Sep 2019 13:08:11 +0200 Subject: [PATCH] Large rework of tables --- src/Binder/Binder.cpp | 63 ++++-- .../BoundExpressions/BoundExpression.hpp | 3 +- src/Diagnostics/DiagnosticCode.hpp | 1 + src/Evaluator/EvalValues/EvalValue.hpp | 6 + .../EvalValues/NumericalTableEvalValue.cpp | 21 -- .../EvalValues/NumericalTableEvalValue.hpp | 84 -------- src/Evaluator/EvalValues/TableEvalValue.cpp | 20 +- src/Evaluator/EvalValues/TableEvalValue.hpp | 37 +++- src/Evaluator/Evaluator.cpp | 30 ++- .../Iterator/NumericalKeyIterator.cpp | 5 + .../Iterator/NumericalKeyIterator.hpp | 29 +-- src/Evaluator/Iterator/SimpleKeyIterator.hpp | 3 +- src/ScriptTypes/ScriptType.cpp | 14 +- src/ScriptTypes/ScriptType.hpp | 57 ++--- src/ScriptTypes/TableScriptType.hpp | 199 +++++++++++++----- .../UserDataCollectionType.hpp | 11 +- src/UserData/UserDataFunctionType.hpp | 4 +- src/UserData/UserDataScriptType.hpp | 32 ++- tests/integration/TablesTests.cpp | 12 ++ 19 files changed, 360 insertions(+), 271 deletions(-) delete mode 100644 src/Evaluator/EvalValues/NumericalTableEvalValue.cpp delete mode 100644 src/Evaluator/EvalValues/NumericalTableEvalValue.hpp diff --git a/src/Binder/Binder.cpp b/src/Binder/Binder.cpp index 7672cb0..a9f1f0b 100644 --- a/src/Binder/Binder.cpp +++ b/src/Binder/Binder.cpp @@ -102,18 +102,35 @@ namespace Porygon::Binder { auto s = (ParsedIndexAssignmentStatement *) statement; auto indexExp = s->GetIndexExpression(); const BoundExpression *indexable; - if (indexExp->GetKind() == ParsedExpressionKind::Indexer) { - indexable = this->BindIndexExpression((IndexExpression *) indexExp, true); - } else { - indexable = this->BindPeriodIndexExpression((PeriodIndexExpression *) indexExp, true); - } auto valueExpression = this->BindExpression(s->GetValueExpression()); - auto boundIndexType = indexable->GetType(); - if (boundIndexType->GetClass() != TypeClass::Error && - boundIndexType->operator!=(valueExpression->GetType())) { - this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidTableValueType, - statement->GetStartPosition(), statement->GetLength()); - return new BoundBadStatement(); + auto valueType = valueExpression->GetType(); + + if (indexExp->GetKind() == ParsedExpressionKind::Indexer) { + auto exp = dynamic_cast(indexExp); + auto indexParent = this->BindExpression(exp->GetIndexer()); + auto indexChild = this->BindExpression(exp->GetIndex()); + auto t = indexParent->GetType(); + if (!t->CanSetIndexValue(indexChild->GetType(), valueType)){ + this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantIndexAssign, + statement->GetStartPosition(), statement->GetLength()); + return new BoundBadStatement(); + } + t->SetIndexValue(indexChild->GetType(), valueType); + indexable = new BoundIndexExpression(indexParent, indexChild, indexChild->GetType(), indexParent->GetStartPosition(), + exp->GetStartPosition() - exp->GetEndPosition()); + } else { + auto exp = dynamic_cast(indexExp); + auto indexParent = this->BindExpression(exp->GetIndexer()); + const auto& key = exp->GetIndex(); + auto t = indexParent->GetType(); + if (!t->CanSetIndexValue(key, valueType)){ + this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantIndexAssign, + statement->GetStartPosition(), statement->GetLength()); + return new BoundBadStatement(); + } + t->SetIndexValue(key, valueType); + indexable = new BoundPeriodIndexExpression(indexParent, key, valueType, indexParent->GetStartPosition(), + exp->GetStartPosition() - exp->GetEndPosition()); } return new BoundIndexAssignmentStatement(indexable, valueExpression); @@ -326,7 +343,7 @@ namespace Porygon::Binder { auto isValueVariableDefined = valueIdentifier.GetHash() != 0; const BoundVariableKey *valueVariable = nullptr; if (isValueVariableDefined) { - auto valueType = itType->GetIndexedType(keyType.get()); + auto valueType = itType->GetIndexedType(keyType); auto valueVariableAssignment = this->_scope->CreateExplicitLocal(valueIdentifier, valueType); if (valueVariableAssignment.GetResult() != VariableAssignmentResult::Ok) { this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantAssignVariable, @@ -746,7 +763,8 @@ namespace Porygon::Binder { } if (indexerType->GetClass() == TypeClass::UserData) { auto stringKey = dynamic_pointer_cast(index->GetType()); - auto field = dynamic_pointer_cast(indexerType)->GetField(stringKey->GetHashValue()); + auto field = dynamic_pointer_cast(indexerType) + ->GetField(stringKey->GetHashValue().GetHash()); if (!setter) { if (!field->HasGetter()) { this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UserDataFieldNoGetter, @@ -764,7 +782,7 @@ namespace Porygon::Binder { } } - auto resultType = indexer->GetType()->GetIndexedType(index->GetType().get()); + auto resultType = indexer->GetType()->GetIndexedType(index->GetType()); return new BoundIndexExpression(indexer, index, resultType, expression->GetStartPosition(), expression->GetLength()); } @@ -816,13 +834,19 @@ namespace Porygon::Binder { this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidTableValueType, boundExpressions[i]->GetStartPosition(), boundExpressions[i]->GetLength()); + return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength()); } } } + else{ + auto tableType = std::make_shared(); + return new BoundNumericalTableExpression(boundExpressions, tableType, expression->GetStartPosition(), + expression->GetLength()); + } if (valueType == nullptr) { valueType = ScriptType::NilType; } - auto tableType = std::make_shared(valueType); + auto tableType = std::make_shared(valueType); return new BoundNumericalTableExpression(boundExpressions, tableType, expression->GetStartPosition(), expression->GetLength()); } @@ -835,7 +859,14 @@ namespace Porygon::Binder { auto block = dynamic_cast(this->BindBlockStatement(expression->GetBlock())); this->_scope = currentScope; - auto tableType = std::make_shared(tableScope, innerScope->GetLocalVariableCount()); + auto dictionary = new unordered_map>(); + for (auto i : *tableScope){ + dictionary->insert({i.first, i.second->GetType()}); + delete i.second; + } + delete tableScope; + + auto tableType = std::make_shared(dictionary); delete innerScope; return new BoundTableExpression(block, tableType, expression->GetStartPosition(), expression->GetLength()); diff --git a/src/Binder/BoundExpressions/BoundExpression.hpp b/src/Binder/BoundExpressions/BoundExpression.hpp index 48c495e..b8c48a9 100644 --- a/src/Binder/BoundExpressions/BoundExpression.hpp +++ b/src/Binder/BoundExpressions/BoundExpression.hpp @@ -145,7 +145,8 @@ namespace Porygon::Binder { public: BoundLiteralStringExpression(const u16string &value, unsigned int start, unsigned int length) : BoundExpression(start, length, - make_shared(true, Utilities::HashedString::ConstHash(value.c_str()))), + make_shared(true, + Utilities::HashedString(new u16string(value)))), _value(value) { } diff --git a/src/Diagnostics/DiagnosticCode.hpp b/src/Diagnostics/DiagnosticCode.hpp index 317f23b..8ac6bb4 100644 --- a/src/Diagnostics/DiagnosticCode.hpp +++ b/src/Diagnostics/DiagnosticCode.hpp @@ -18,6 +18,7 @@ namespace Porygon::Diagnostics { VariableNotFound, ExpressionIsNotAFunction, CantIndex, + CantIndexAssign, InvalidReturnType, ConditionNotABool, InvalidTableValueType, diff --git a/src/Evaluator/EvalValues/EvalValue.hpp b/src/Evaluator/EvalValues/EvalValue.hpp index 4912570..f6bc804 100644 --- a/src/Evaluator/EvalValues/EvalValue.hpp +++ b/src/Evaluator/EvalValues/EvalValue.hpp @@ -77,6 +77,12 @@ namespace Porygon::Evaluation { throw EvaluationException(err.str()); } + virtual void SetIndexValue(const Utilities::HashedString *key, const EvalValue* value) const { + std::stringstream err; + err << "Can't index this EvalValue: " << ToString() << " with key: " << value->ToString(); + throw EvaluationException(err.str()); + } + [[nodiscard]] virtual Iterator * GetKeyIterator() const{ throw EvaluationException("Can't iterate over this EvalValue"); diff --git a/src/Evaluator/EvalValues/NumericalTableEvalValue.cpp b/src/Evaluator/EvalValues/NumericalTableEvalValue.cpp deleted file mode 100644 index 50c9d46..0000000 --- a/src/Evaluator/EvalValues/NumericalTableEvalValue.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "NumericalTableEvalValue.hpp" -#include "../Iterator/NumericalKeyIterator.hpp" -#include "../../Utilities/Random.hpp" - -inline Porygon::Evaluation::Iterator *Porygon::Evaluation::NumericalTableEvalValue::GetKeyIterator() const { - return new NumericalKeyIterator(this); -} - -Porygon::Evaluation::NumericalTableEvalValue::NumericalTableEvalValue(shared_ptr> table) : - _table(std::move(table)), - _hash(Utilities::Random::Get()) -{ -} - -Porygon::Evaluation::EvalValue * -Porygon::Evaluation::NumericalTableEvalValue::UnaryOperation(Porygon::Binder::BoundUnaryOperation operation) const { - if (operation == Porygon::Binder::BoundUnaryOperation::Count){ - return new NumericEvalValue(static_cast(this->_table->size())); - } - return EvalValue::UnaryOperation(operation); -} diff --git a/src/Evaluator/EvalValues/NumericalTableEvalValue.hpp b/src/Evaluator/EvalValues/NumericalTableEvalValue.hpp deleted file mode 100644 index f62e15a..0000000 --- a/src/Evaluator/EvalValues/NumericalTableEvalValue.hpp +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef PORYGONLANG_NUMERICALTABLEEVALVALUE_HPP -#define PORYGONLANG_NUMERICALTABLEEVALVALUE_HPP - - -#include -#include -#include "EvalValue.hpp" -#include "../EvalValuePointer.hpp" - -using namespace std; - -namespace Porygon::Evaluation { - class NumericalTableEvalValue : public EvalValue { - const shared_ptr> _table; - const size_t _hash; - - explicit NumericalTableEvalValue(shared_ptr> table, size_t hash) - : _table(std::move(table)), - _hash(hash) - { - } - - public: - explicit NumericalTableEvalValue(shared_ptr> table); - - [[nodiscard]] - inline TypeClass GetTypeClass() const final { - return TypeClass::Table; - } - - [[nodiscard]] - inline size_t GetHashCode() const final { - return _hash; - } - - [[nodiscard]] - inline bool operator==(const EvalValue *b) const final { - return this->_hash == b->GetHashCode(); - } - - bool operator!=(const EvalValue *b) const override { - return !operator==(b); - } - - [[nodiscard]] - inline EvalValue* Clone() const final { - return new NumericalTableEvalValue(_table, _hash); - } - - [[nodiscard]] - inline const EvalValue* IndexValue(const EvalValue *val) const final { - const auto index = val->EvaluateInteger() - 1; - return this->_table->at(index).Clone(); - } - - [[nodiscard]] - inline EvalValue* IndexValue(const Utilities::HashedString* hash) const final { - return this->_table->at(hash->GetHash() - 1)-> Clone(); - } - - inline void SetIndexValue(const EvalValue *key, const EvalValue* value) const final { - auto index = key->EvaluateInteger(); - index--; - if (this->_table->size() <= index){ - this->_table->resize(index); - } - this->_table->at(index) = value; - } - - [[nodiscard]] - Iterator * GetKeyIterator() const final; - - [[nodiscard]] - inline shared_ptr> GetTable() const{ - return _table; - } - - [[nodiscard]] EvalValue *UnaryOperation(Binder::BoundUnaryOperation operation) const override;; - }; -} - -#undef iteratorKind - -#endif //PORYGONLANG_NUMERICALTABLEEVALVALUE_HPP diff --git a/src/Evaluator/EvalValues/TableEvalValue.cpp b/src/Evaluator/EvalValues/TableEvalValue.cpp index 2995a5b..3ce6906 100644 --- a/src/Evaluator/EvalValues/TableEvalValue.cpp +++ b/src/Evaluator/EvalValues/TableEvalValue.cpp @@ -1,8 +1,9 @@ #include "TableEvalValue.hpp" #include "../Iterator/SimpleKeyIterator.hpp" #include "NumericEvalValue.hpp" +#include "../Iterator/NumericalKeyIterator.hpp" -inline Porygon::Evaluation::Iterator * Porygon::Evaluation::TableEvalValue::GetKeyIterator() const { +Porygon::Evaluation::Iterator * Porygon::Evaluation::TableEvalValue::GetKeyIterator() const { return new TableKeyIterator(this); } @@ -13,3 +14,20 @@ Porygon::Evaluation::TableEvalValue::UnaryOperation(Porygon::Binder::BoundUnaryO } return EvalValue::UnaryOperation(operation); } + +void Porygon::Evaluation::TableEvalValue::SetIndexValue(const Porygon::Utilities::HashedString *key, + const Porygon::Evaluation::EvalValue *value) const { + auto insert = _table->insert({*key, value}); + if (!insert.second) { + _table->at(*key).ClearAssign(value); + } + +} + +Porygon::Evaluation::Iterator *Porygon::Evaluation::NumericTableEvalValue::GetKeyIterator() const { + return new NumericalKeyIterator(this); +} + +Porygon::Evaluation::EvalValue *Porygon::Evaluation::NumericTableEvalValue::Clone() const { + return new NumericTableEvalValue(_table, _hash); +} diff --git a/src/Evaluator/EvalValues/TableEvalValue.hpp b/src/Evaluator/EvalValues/TableEvalValue.hpp index 843653f..36cad69 100644 --- a/src/Evaluator/EvalValues/TableEvalValue.hpp +++ b/src/Evaluator/EvalValues/TableEvalValue.hpp @@ -11,15 +11,15 @@ using namespace std; namespace Porygon::Evaluation { class TableEvalValue : public EvalValue { - const shared_ptr> _table; - const size_t _hash; - + protected: explicit TableEvalValue(shared_ptr> table, size_t hash) : _table(std::move(table)), _hash(hash) { } + const shared_ptr> _table; + const size_t _hash; public: explicit TableEvalValue(shared_ptr> table) : _table(std::move(table)), @@ -47,7 +47,7 @@ namespace Porygon::Evaluation { } [[nodiscard]] - inline EvalValue* Clone() const final { + inline EvalValue* Clone() const override { return new TableEvalValue(_table, _hash); } @@ -70,11 +70,15 @@ namespace Porygon::Evaluation { inline void SetIndexValue(const EvalValue *key, const EvalValue* value) const final { auto hash = key->GetHashCode(); - this->_table->at(Utilities::HashedString::CreateLookup(hash)).ClearAssign(value); + auto lookup = Utilities::HashedString::CreateLookup(hash); + auto insert = _table->insert({lookup, value}); + if (!insert.second) { + _table->at(lookup).ClearAssign(value); + } } [[nodiscard]] - Iterator * GetKeyIterator() const final; + Iterator * GetKeyIterator() const override; [[nodiscard]] inline _Rb_tree_const_iterator> GetTableIterator() const{ @@ -85,7 +89,26 @@ namespace Porygon::Evaluation { return _table->cend(); } - EvalValue *UnaryOperation(Binder::BoundUnaryOperation operation) const override;; + [[nodiscard]] EvalValue *UnaryOperation(Binder::BoundUnaryOperation operation) const override; + + void SetIndexValue(const Utilities::HashedString *key, const EvalValue *value) const override; + }; + + class NumericTableEvalValue : public TableEvalValue{ + + explicit NumericTableEvalValue(shared_ptr> table, size_t hash) + : TableEvalValue(std::move(table), hash) + { + } + public: + explicit NumericTableEvalValue(shared_ptr> table) + :TableEvalValue(std::move(table)) + { + } + + [[nodiscard]] Iterator *GetKeyIterator() const final; + + [[nodiscard]] EvalValue *Clone() const override; }; } diff --git a/src/Evaluator/Evaluator.cpp b/src/Evaluator/Evaluator.cpp index df1e33d..d409b58 100644 --- a/src/Evaluator/Evaluator.cpp +++ b/src/Evaluator/Evaluator.cpp @@ -11,7 +11,6 @@ #include "../Binder/BoundExpressions/BoundRequireExpression.hpp" #include "../ScriptTypes/TableScriptType.hpp" #include "../UserData/UserDataFunction.hpp" -#include "EvalValues/NumericalTableEvalValue.hpp" #include "../UserData/UserDataValue.hpp" using namespace std; @@ -93,12 +92,21 @@ namespace Porygon::Evaluation { void Evaluator::EvaluateIndexAssignmentStatement(const BoundIndexAssignmentStatement *statement) { auto indexExpression = statement->GetIndexExpression(); auto value = this->EvaluateExpression(statement->GetValueExpression()); - auto index = ((BoundIndexExpression *) indexExpression); - auto table = this->EvaluateExpression(index->GetIndexableExpression()); - auto key = this->EvaluateExpression(index->GetIndexExpression()); - table->SetIndexValue(key.Get(), value.Take()); + if (indexExpression->GetKind() == BoundExpressionKind::Index){ + auto index = dynamic_cast(indexExpression); + auto table = this->EvaluateExpression(index->GetIndexableExpression()); + auto key = this->EvaluateExpression(index->GetIndexExpression()); + table->SetIndexValue(key.Get(), value.Take()); + } + else{ + auto index = dynamic_cast(indexExpression); + auto table = this->EvaluateExpression(index->GetIndexableExpression()); + auto key = index->GetIndex(); + table->SetIndexValue(key, value.Take()); + } } + void Evaluator::EvaluateFunctionDeclarationStatement(const BoundFunctionDeclarationStatement *statement) { auto type = statement->GetType(); auto key = statement->GetKey(); @@ -396,20 +404,22 @@ namespace Porygon::Evaluation { EvalValuePointer Evaluator::EvaluateNumericTableExpression(const BoundExpression *expression) { auto tableExpression = (BoundNumericalTableExpression *) expression; auto valueExpressions = tableExpression->GetExpressions(); - auto values = new vector(valueExpressions->size()); + auto values = new map(); for (size_t i = 0; i < valueExpressions->size(); i++) { auto val = this->EvaluateExpression(valueExpressions->at(i)); - values->at(i) = val.Take(); + auto k = Utilities::StringUtils::IntToString(i + 1); + auto s = Utilities::HashedString(new u16string(k)); + values->insert({s, val}); } - auto valuesPointer = shared_ptr>(values); - return new NumericalTableEvalValue(valuesPointer); + auto valuesPointer = shared_ptr>(values); + return new NumericTableEvalValue(valuesPointer); } EvalValuePointer Evaluator::EvaluateComplexTableExpression(const BoundExpression *expression) { auto tableExpression = (BoundTableExpression *) expression; const auto& baseType = tableExpression -> GetType(); auto type = dynamic_pointer_cast(baseType); - auto declaredVars = type->GetValues(); + auto declaredVars = type->GetContentTypes(); auto variables = make_shared>(); for (const auto& i : *declaredVars) { variables->insert({i.first, nullptr}); diff --git a/src/Evaluator/Iterator/NumericalKeyIterator.cpp b/src/Evaluator/Iterator/NumericalKeyIterator.cpp index 488cc46..d4149ef 100644 --- a/src/Evaluator/Iterator/NumericalKeyIterator.cpp +++ b/src/Evaluator/Iterator/NumericalKeyIterator.cpp @@ -1 +1,6 @@ #include "NumericalKeyIterator.hpp" + +const Porygon::Evaluation::EvalValue *Porygon::Evaluation::NumericalKeyIterator::GetCurrent() { + auto s = *_iterator->first.GetString(); + return new NumericEvalValue(Utilities::StringUtils::ParseInteger(s)); +} diff --git a/src/Evaluator/Iterator/NumericalKeyIterator.hpp b/src/Evaluator/Iterator/NumericalKeyIterator.hpp index 29694dd..b96c32c 100644 --- a/src/Evaluator/Iterator/NumericalKeyIterator.hpp +++ b/src/Evaluator/Iterator/NumericalKeyIterator.hpp @@ -1,34 +1,15 @@ #ifndef PORYGONLANG_NUMERICALKEYITERATOR_HPP #define PORYGONLANG_NUMERICALKEYITERATOR_HPP - -#include "Iterator.hpp" -#include "../EvalValues/NumericalTableEvalValue.hpp" -#include "../EvalValues/NumericEvalValue.hpp" - +#include "SimpleKeyIterator.hpp" namespace Porygon::Evaluation{ - class NumericalKeyIterator : public Iterator{ - const shared_ptr> _vec; - const size_t _size; - size_t _position = 0; + class NumericalKeyIterator : public TableKeyIterator{ public: - explicit NumericalKeyIterator(const NumericalTableEvalValue* table) - : _vec(table->GetTable()), _size(_vec->size() + 1){} + const EvalValue *GetCurrent() override; + explicit NumericalKeyIterator(const TableEvalValue* table) + : TableKeyIterator(table){} - inline const EvalValue* GetCurrent() final{ - return new NumericEvalValue(static_cast(_position)); - } - - inline bool MoveNext() final{ - _position++; - return _position != _size; - } - - inline void Reset() final{ - _position = 0; - } }; } - #endif //PORYGONLANG_NUMERICALKEYITERATOR_HPP diff --git a/src/Evaluator/Iterator/SimpleKeyIterator.hpp b/src/Evaluator/Iterator/SimpleKeyIterator.hpp index 4bd3996..73b96f0 100644 --- a/src/Evaluator/Iterator/SimpleKeyIterator.hpp +++ b/src/Evaluator/Iterator/SimpleKeyIterator.hpp @@ -8,6 +8,7 @@ namespace Porygon::Evaluation{ class TableKeyIterator : public Iterator{ + protected: _Rb_tree_const_iterator> _iterator; _Rb_tree_const_iterator> _end; bool _hasStarted = false; @@ -15,7 +16,7 @@ namespace Porygon::Evaluation{ explicit TableKeyIterator(const TableEvalValue* table) : _iterator(table->GetTableIterator()), _end(table->GetTableIteratorEnd()){} - inline const EvalValue* GetCurrent() final{ + inline const EvalValue* GetCurrent() override { return new StringEvalValue(*_iterator->first.GetString()); } diff --git a/src/ScriptTypes/ScriptType.cpp b/src/ScriptTypes/ScriptType.cpp index aebc1bf..a9b39ad 100644 --- a/src/ScriptTypes/ScriptType.cpp +++ b/src/ScriptTypes/ScriptType.cpp @@ -1,6 +1,5 @@ #include "../Script.hpp" #include "../UserData/UserDataFunctionType.hpp" -#include "ScriptType.hpp" namespace Porygon{ @@ -11,12 +10,13 @@ namespace Porygon{ shared_ptr ScriptType::BoolType = make_shared(TypeClass::Bool); shared_ptr ScriptType::NilType = make_shared(TypeClass::Nil); shared_ptr ScriptType::AnyType = make_shared(TypeClass::Any); - shared_ptr NumericScriptType::AwareInt = make_shared(true, false); - shared_ptr NumericScriptType::AwareFloat = make_shared(true, true); - shared_ptr NumericScriptType::Unaware = make_shared(false, false); - shared_ptr StringScriptType::Dynamic = make_shared(false, 0); + shared_ptr NumericScriptType::AwareInt = make_shared(true, false); + shared_ptr NumericScriptType::AwareFloat = make_shared(true, true); + shared_ptr NumericScriptType::Unaware = make_shared(false, false); + shared_ptr StringScriptType::Dynamic = make_shared(false, + Utilities::HashedString::CreateLookup(0)); - shared_ptr ScriptType::GetIndexedType(const ScriptType*) const{ + shared_ptr ScriptType::GetIndexedType(shared_ptr) const{ return make_shared(TypeClass::Error); } @@ -96,7 +96,7 @@ namespace Porygon{ } ScriptType* CreateStringScriptType(bool knownAtBind, uint32_t hash){ - return new StringScriptType(knownAtBind, hash); + return new StringScriptType(knownAtBind, Utilities::HashedString::CreateLookup(hash)); } ScriptType* CreateUserDataFunctionScriptType(ScriptType* returnType, ScriptType* parameters[], size_t parameterCount){ diff --git a/src/ScriptTypes/ScriptType.hpp b/src/ScriptTypes/ScriptType.hpp index b63bb76..3d20a43 100644 --- a/src/ScriptTypes/ScriptType.hpp +++ b/src/ScriptTypes/ScriptType.hpp @@ -43,9 +43,19 @@ namespace Porygon{ virtual bool CanBeIndexedWith(const ScriptType* indexer) const; [[nodiscard]] virtual bool CanBeIndexedWithIdentifier(uint32_t hash) const; - [[nodiscard]] virtual shared_ptr GetIndexedType(const ScriptType* indexer) const; + [[nodiscard]] virtual shared_ptr GetIndexedType(shared_ptr indexer) const; [[nodiscard]] virtual shared_ptr GetIndexedType(uint32_t hash) const; + [[nodiscard]] virtual bool CanSetIndexValue(shared_ptr indexer, shared_ptr val) const{ + return false; + } + [[nodiscard]] virtual bool CanSetIndexValue(Utilities::HashedString indexer, shared_ptr val) const{ + return false; + } + + virtual void SetIndexValue(shared_ptr indexer, shared_ptr val) const { } + virtual void SetIndexValue(Utilities::HashedString indexer, shared_ptr val) const { } + [[nodiscard]] virtual bool CanBeIterated() const; [[nodiscard]] virtual shared_ptr GetIteratorKeyType() const; @@ -104,6 +114,8 @@ namespace Porygon{ } [[nodiscard]] CastResult CastableTo(const shared_ptr& castType, bool explicitCast) const final{ + if (this->operator==(castType)) + return CastResult ::ValidCast; if (!explicitCast){ if (castType->GetClass() != TypeClass::Number ) return CastResult::InvalidCast; @@ -117,11 +129,11 @@ namespace Porygon{ class StringScriptType : public ScriptType{ bool _isKnownAtBind; - uint32_t _hashValue; + Utilities::HashedString _hashValue; public: - explicit StringScriptType(bool knownAtBind, uint32_t hashValue): ScriptType(TypeClass::String){ + explicit StringScriptType(bool knownAtBind, const Utilities::HashedString& hashValue) + : ScriptType(TypeClass::String), _hashValue(hashValue){ _isKnownAtBind = knownAtBind; - _hashValue = hashValue; } static shared_ptr Dynamic; @@ -134,7 +146,7 @@ namespace Porygon{ return !(num->IsAwareOfFloat() && num->IsFloat()); } - inline shared_ptr GetIndexedType(const ScriptType* indexer) const final{ + inline shared_ptr GetIndexedType(shared_ptr indexer) const final{ return StringScriptType::Dynamic; } @@ -144,45 +156,12 @@ namespace Porygon{ } [[nodiscard]] - inline uint32_t GetHashValue() const{ + inline Utilities::HashedString GetHashValue() const{ return _hashValue; } bool IsCountable() const override; }; - - class NumericalTableScriptType : public ScriptType{ - shared_ptr _valueType; - // Consider adding a check whether the table actually contains a type if every key is static. - public: - explicit NumericalTableScriptType(shared_ptr valueType) - : ScriptType(TypeClass::Table), _valueType(std::move(valueType)){ - } - - bool CanBeIndexedWith(const ScriptType* indexer) const final{ - if (indexer -> GetClass() != TypeClass::Number) - return false; - auto num = dynamic_cast(indexer); - return !(num->IsAwareOfFloat() && num->IsFloat()); - } - - inline shared_ptr GetIndexedType(const ScriptType* indexer) const final{ - return _valueType; - } - - [[nodiscard]] - inline bool CanBeIterated() const final{ - return true; - } - [[nodiscard]] - inline shared_ptr GetIteratorKeyType() const final{ - return NumericScriptType::AwareInt; - } - - [[nodiscard]] bool IsCountable() const override { - return true; - } - }; } diff --git a/src/ScriptTypes/TableScriptType.hpp b/src/ScriptTypes/TableScriptType.hpp index dccdd64..5293cb3 100644 --- a/src/ScriptTypes/TableScriptType.hpp +++ b/src/ScriptTypes/TableScriptType.hpp @@ -2,72 +2,165 @@ #ifndef PORYGONLANG_TABLESCRIPTTYPE_HPP #define PORYGONLANG_TABLESCRIPTTYPE_HPP #include +#include #include "../Binder/BoundVariables/BoundVariable.hpp" +#include "../Exception.hpp" namespace Porygon{ + class TableScriptType : public ScriptType{ - const map* _values; - const int _localVariableCount; + enum TableType{ + Unknown, + Numerical, + StringKeyed, + Dictionary + }; + + bool _isContentAware; + TableType _tableType; + + union{ + shared_ptr _valueType; // numerical + unordered_map>* _contentTypes = nullptr; // string keyed + std::pair, shared_ptr> _keyValueType; // dictionary + }; + public: - explicit TableScriptType(map* values, int localVariableCount) - : ScriptType(TypeClass::Table), - _values(values), - _localVariableCount(localVariableCount) - {} - explicit TableScriptType() - : ScriptType(TypeClass::Table), - _values(nullptr), - _localVariableCount(0) - {} + : ScriptType(TypeClass::Table), _tableType(TableType::Unknown) {} + explicit TableScriptType(shared_ptr valueType) + : ScriptType(TypeClass::Table), _tableType(TableType::Numerical), _valueType(std::move(valueType)) {} - ~TableScriptType() final{ - if (_values != nullptr){ - for (const auto& i : *_values){ - delete i.second; + 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 _contentTypes; + } + + [[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 = _keyValueType.first; + return indexer->CastableTo(keyType, false) != CastResult ::InvalidCast; + } + } + + [[nodiscard]] bool CanBeIndexedWithIdentifier(uint32_t hash) const override { + if (_tableType != TableType::StringKeyed) + return false; + return _isContentAware; + } + + 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 _contentTypes->at(h); + } + return ScriptType::AnyType; + } + else if (_tableType == TableType::Numerical){ + return _valueType; + } + else{ + return _keyValueType.second; + } + } + + [[nodiscard]] shared_ptr GetIndexedType(uint32_t hash) const override { + auto lookup = Utilities::HashedString::CreateLookup(hash); + return _contentTypes->at(lookup); + } + + unordered_map>* GetContentTypes() const{ + return _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(_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; + } + } + + [[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(); + _contentTypes->insert({key, val}); } } - delete _values; } - [[nodiscard]] - inline bool CanBeIndexedWith(const ScriptType* indexer) const final{ - return indexer->GetClass() == TypeClass ::String; - } - - [[nodiscard]] bool CanBeIndexedWithIdentifier(uint32_t hash) const final{ - return true; - } - - shared_ptr GetIndexedType(const ScriptType* indexer) const final{ - auto stringKey = dynamic_cast(indexer); - if (stringKey != nullptr && stringKey->IsKnownAtBind() && _values != nullptr){ - return _values-> at(Utilities::HashedString::CreateLookup(stringKey->GetHashValue()))->GetType(); + void SetIndexValue(Utilities::HashedString indexer, shared_ptr val) const override { + if (_tableType == TableType::StringKeyed){ + _contentTypes->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} + }; } - return make_shared(TypeClass::Any); - } - - [[nodiscard]] inline shared_ptr GetIndexedType(uint32_t hash) const final{ - return _values-> at(Utilities::HashedString::CreateLookup(hash))->GetType(); - } - - [[nodiscard]] inline const map* GetValues() const{ - return _values; - } - - [[nodiscard]] - bool CanBeIterated() const final { - return true; - } - - [[nodiscard]] - shared_ptr GetIteratorKeyType() const final { - return make_shared(TypeClass::Any); - } - - bool IsCountable() const override { - return true; } }; } diff --git a/src/UserData/UserDataCollections/UserDataCollectionType.hpp b/src/UserData/UserDataCollections/UserDataCollectionType.hpp index 3d791f7..8f42bd3 100644 --- a/src/UserData/UserDataCollections/UserDataCollectionType.hpp +++ b/src/UserData/UserDataCollections/UserDataCollectionType.hpp @@ -51,7 +51,7 @@ namespace Porygon::UserData { return indexer->operator==(_keyType); } - [[nodiscard]] shared_ptr GetIndexedType(const ScriptType* indexer) const final{ + [[nodiscard]] shared_ptr GetIndexedType(shared_ptr indexer) const final{ return _valueType; } @@ -70,6 +70,15 @@ namespace Porygon::UserData { [[nodiscard]] bool IsCountable() const override { return true; } + + [[nodiscard]] + bool CanSetIndexValue(shared_ptr indexer, shared_ptr val) const override { + if (indexer->CastableTo(_keyType, false) == CastResult::InvalidCast) + return false; + if (val->CastableTo(_valueType, false) == CastResult::InvalidCast) + return false; + return true; + } }; } diff --git a/src/UserData/UserDataFunctionType.hpp b/src/UserData/UserDataFunctionType.hpp index c63eaf4..efcc19f 100644 --- a/src/UserData/UserDataFunctionType.hpp +++ b/src/UserData/UserDataFunctionType.hpp @@ -12,11 +12,11 @@ namespace Porygon::UserData{ : GenericFunctionOption(std::move(returnType), std::move(parameterTypes)) { } - static UserDataFunctionOption* FromRawPointers(const ScriptType* returnType, vector parameterTypes){ + static UserDataFunctionOption* FromRawPointers(ScriptType* returnType, vector parameterTypes){ auto rt = shared_ptr(returnType); auto p = vector>(parameterTypes.size()); for (size_t i = 0; i < parameterTypes.size(); i++){ - p[i] = shared_ptr(parameterTypes[i]); + p[i] = shared_ptr(parameterTypes[i]); } return new UserDataFunctionOption(rt, p); } diff --git a/src/UserData/UserDataScriptType.hpp b/src/UserData/UserDataScriptType.hpp index cf64226..55651af 100644 --- a/src/UserData/UserDataScriptType.hpp +++ b/src/UserData/UserDataScriptType.hpp @@ -36,7 +36,7 @@ namespace Porygon::UserData { auto str = dynamic_cast(indexer); if (!str->IsKnownAtBind()) return false; - return _userData->Get()->ContainsField(str->GetHashValue()); + return _userData->Get()->ContainsField(str->GetHashValue().GetHash()); } [[nodiscard]] inline bool CanBeIndexedWithIdentifier(uint32_t hash) const final { @@ -47,10 +47,10 @@ namespace Porygon::UserData { return _userData->Get()->GetField(id); } - shared_ptr GetIndexedType(const ScriptType *indexer) const final { - auto stringKey = dynamic_cast(indexer); + shared_ptr GetIndexedType(shared_ptr indexer) const final { + auto stringKey = dynamic_pointer_cast(indexer); if (stringKey->IsKnownAtBind()) { - return _userData->Get()->GetField(stringKey->GetHashValue())->GetType(); + return _userData->Get()->GetField(stringKey->GetHashValue().GetHash())->GetType(); } throw "TODO: indexing with dynamic keys"; } @@ -72,6 +72,30 @@ namespace Porygon::UserData { return s.str(); } + [[nodiscard]] + bool CanSetIndexValue(shared_ptr indexer, shared_ptr val) const override { + if (indexer->GetClass() != TypeClass::String) + return false; + auto s = dynamic_pointer_cast(indexer); + if (!s->IsKnownAtBind()) + return false; + auto hash = s->GetHashValue(); + auto ud = _userData->Get(); + if (!ud->ContainsField(hash.GetHash())) + return false; + auto field = _userData->Get()->GetField(hash.GetHash()); + return (val->CastableTo(field->GetType(), false) != CastResult::InvalidCast); + + } + + [[nodiscard]] bool CanSetIndexValue(Utilities::HashedString indexer, shared_ptr val) const override { + auto ud = _userData->Get(); + if (ud->ContainsField(indexer.GetHash())) + return false; + auto field = _userData->Get()->GetField(indexer.GetHash()); + return (val->CastableTo(field->GetType(), false) != CastResult::InvalidCast); + } + }; } diff --git a/tests/integration/TablesTests.cpp b/tests/integration/TablesTests.cpp index ad49ab3..97941a3 100644 --- a/tests/integration/TablesTests.cpp +++ b/tests/integration/TablesTests.cpp @@ -87,6 +87,18 @@ return table["getFoo"]() delete script; } +TEST_CASE( "Dynamic table size", "[integration]" ) { + Script* script = Script::Create( + R"( +table = {} +table.foo = 500 +)"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + delete script; +} + + #endif