Large rework of tables
continuous-integration/drone/push Build is failing Details

This commit is contained in:
Deukhoofd 2019-09-15 13:08:11 +02:00
parent e89782f921
commit 458274f370
Signed by: Deukhoofd
GPG Key ID: ADF2E9256009EDCE
19 changed files with 360 additions and 271 deletions

View File

@ -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<const IndexExpression*>(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<const PeriodIndexExpression*>(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<const StringScriptType>(index->GetType());
auto field = dynamic_pointer_cast<const UserData::UserDataScriptType>(indexerType)->GetField(stringKey->GetHashValue());
auto field = dynamic_pointer_cast<const UserData::UserDataScriptType>(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<const TableScriptType>();
return new BoundNumericalTableExpression(boundExpressions, tableType, expression->GetStartPosition(),
expression->GetLength());
}
if (valueType == nullptr) {
valueType = ScriptType::NilType;
}
auto tableType = std::make_shared<const NumericalTableScriptType>(valueType);
auto tableType = std::make_shared<const TableScriptType>(valueType);
return new BoundNumericalTableExpression(boundExpressions, tableType, expression->GetStartPosition(),
expression->GetLength());
}
@ -835,7 +859,14 @@ namespace Porygon::Binder {
auto block = dynamic_cast<BoundBlockStatement*>(this->BindBlockStatement(expression->GetBlock()));
this->_scope = currentScope;
auto tableType = std::make_shared<TableScriptType>(tableScope, innerScope->GetLocalVariableCount());
auto dictionary = new unordered_map<HashedString, shared_ptr<const ScriptType>>();
for (auto i : *tableScope){
dictionary->insert({i.first, i.second->GetType()});
delete i.second;
}
delete tableScope;
auto tableType = std::make_shared<TableScriptType>(dictionary);
delete innerScope;
return new BoundTableExpression(block, tableType, expression->GetStartPosition(), expression->GetLength());

View File

@ -145,7 +145,8 @@ namespace Porygon::Binder {
public:
BoundLiteralStringExpression(const u16string &value, unsigned int start, unsigned int length)
: BoundExpression(start, length,
make_shared<StringScriptType>(true, Utilities::HashedString::ConstHash(value.c_str()))),
make_shared<StringScriptType>(true,
Utilities::HashedString(new u16string(value)))),
_value(value) {
}

View File

@ -18,6 +18,7 @@ namespace Porygon::Diagnostics {
VariableNotFound,
ExpressionIsNotAFunction,
CantIndex,
CantIndexAssign,
InvalidReturnType,
ConditionNotABool,
InvalidTableValueType,

View File

@ -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");

View File

@ -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<vector<EvalValuePointer>> 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<int64_t>(this->_table->size()));
}
return EvalValue::UnaryOperation(operation);
}

View File

@ -1,84 +0,0 @@
#ifndef PORYGONLANG_NUMERICALTABLEEVALVALUE_HPP
#define PORYGONLANG_NUMERICALTABLEEVALVALUE_HPP
#include <utility>
#include <map>
#include "EvalValue.hpp"
#include "../EvalValuePointer.hpp"
using namespace std;
namespace Porygon::Evaluation {
class NumericalTableEvalValue : public EvalValue {
const shared_ptr<vector<EvalValuePointer>> _table;
const size_t _hash;
explicit NumericalTableEvalValue(shared_ptr<vector<EvalValuePointer>> table, size_t hash)
: _table(std::move(table)),
_hash(hash)
{
}
public:
explicit NumericalTableEvalValue(shared_ptr<vector<EvalValuePointer>> 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<vector<EvalValuePointer>> GetTable() const{
return _table;
}
[[nodiscard]] EvalValue *UnaryOperation(Binder::BoundUnaryOperation operation) const override;;
};
}
#undef iteratorKind
#endif //PORYGONLANG_NUMERICALTABLEEVALVALUE_HPP

View File

@ -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);
}

View File

@ -11,15 +11,15 @@ using namespace std;
namespace Porygon::Evaluation {
class TableEvalValue : public EvalValue {
const shared_ptr<map<Utilities::HashedString, EvalValuePointer>> _table;
const size_t _hash;
protected:
explicit TableEvalValue(shared_ptr<map<Utilities::HashedString, EvalValuePointer>> table, size_t hash)
: _table(std::move(table)),
_hash(hash)
{
}
const shared_ptr<map<Utilities::HashedString, EvalValuePointer>> _table;
const size_t _hash;
public:
explicit TableEvalValue(shared_ptr<map<Utilities::HashedString, EvalValuePointer>> 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<pair<const Utilities::HashedString, EvalValuePointer>> 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<map<Utilities::HashedString, EvalValuePointer>> table, size_t hash)
: TableEvalValue(std::move(table), hash)
{
}
public:
explicit NumericTableEvalValue(shared_ptr<map<Utilities::HashedString, EvalValuePointer>> table)
:TableEvalValue(std::move(table))
{
}
[[nodiscard]] Iterator *GetKeyIterator() const final;
[[nodiscard]] EvalValue *Clone() const override;
};
}

View File

@ -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<const BoundIndexExpression*>(indexExpression);
auto table = this->EvaluateExpression(index->GetIndexableExpression());
auto key = this->EvaluateExpression(index->GetIndexExpression());
table->SetIndexValue(key.Get(), value.Take());
}
else{
auto index = dynamic_cast<const BoundPeriodIndexExpression*>(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<EvalValuePointer>(valueExpressions->size());
auto values = new map<Utilities::HashedString, EvalValuePointer>();
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<vector<EvalValuePointer>>(values);
return new NumericalTableEvalValue(valuesPointer);
auto valuesPointer = shared_ptr<map<Utilities::HashedString, EvalValuePointer>>(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<const TableScriptType>(baseType);
auto declaredVars = type->GetValues();
auto declaredVars = type->GetContentTypes();
auto variables = make_shared<map<Utilities::HashedString, EvalValuePointer>>();
for (const auto& i : *declaredVars) {
variables->insert({i.first, nullptr});

View File

@ -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));
}

View File

@ -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<vector<EvalValuePointer>> _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<int64_t >(_position));
}
inline bool MoveNext() final{
_position++;
return _position != _size;
}
inline void Reset() final{
_position = 0;
}
};
}
#endif //PORYGONLANG_NUMERICALKEYITERATOR_HPP

View File

@ -8,6 +8,7 @@
namespace Porygon::Evaluation{
class TableKeyIterator : public Iterator{
protected:
_Rb_tree_const_iterator<pair<const Utilities::HashedString, EvalValuePointer>> _iterator;
_Rb_tree_const_iterator<pair<const Utilities::HashedString, EvalValuePointer>> _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());
}

View File

@ -1,6 +1,5 @@
#include "../Script.hpp"
#include "../UserData/UserDataFunctionType.hpp"
#include "ScriptType.hpp"
namespace Porygon{
@ -11,12 +10,13 @@ namespace Porygon{
shared_ptr<const ScriptType> ScriptType::BoolType = make_shared<ScriptType>(TypeClass::Bool);
shared_ptr<const ScriptType> ScriptType::NilType = make_shared<ScriptType>(TypeClass::Nil);
shared_ptr<const ScriptType> ScriptType::AnyType = make_shared<ScriptType>(TypeClass::Any);
shared_ptr<const NumericScriptType> NumericScriptType::AwareInt = make_shared<NumericScriptType>(true, false);
shared_ptr<const NumericScriptType> NumericScriptType::AwareFloat = make_shared<NumericScriptType>(true, true);
shared_ptr<const NumericScriptType> NumericScriptType::Unaware = make_shared<NumericScriptType>(false, false);
shared_ptr<const StringScriptType> StringScriptType::Dynamic = make_shared<StringScriptType>(false, 0);
shared_ptr<const NumericScriptType> NumericScriptType::AwareInt = make_shared<const NumericScriptType>(true, false);
shared_ptr<const NumericScriptType> NumericScriptType::AwareFloat = make_shared<const NumericScriptType>(true, true);
shared_ptr<const NumericScriptType> NumericScriptType::Unaware = make_shared<const NumericScriptType>(false, false);
shared_ptr<const StringScriptType> StringScriptType::Dynamic = make_shared<const StringScriptType>(false,
Utilities::HashedString::CreateLookup(0));
shared_ptr<const ScriptType> ScriptType::GetIndexedType(const ScriptType*) const{
shared_ptr<const ScriptType> ScriptType::GetIndexedType(shared_ptr<const ScriptType>) const{
return make_shared<ScriptType>(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){

View File

@ -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<const ScriptType> GetIndexedType(const ScriptType* indexer) const;
[[nodiscard]] virtual shared_ptr<const ScriptType> GetIndexedType(shared_ptr<const ScriptType> indexer) const;
[[nodiscard]] virtual shared_ptr<const ScriptType> GetIndexedType(uint32_t hash) const;
[[nodiscard]] virtual bool CanSetIndexValue(shared_ptr<const ScriptType> indexer, shared_ptr<const ScriptType> val) const{
return false;
}
[[nodiscard]] virtual bool CanSetIndexValue(Utilities::HashedString indexer, shared_ptr<const ScriptType> val) const{
return false;
}
virtual void SetIndexValue(shared_ptr<const ScriptType> indexer, shared_ptr<const ScriptType> val) const { }
virtual void SetIndexValue(Utilities::HashedString indexer, shared_ptr<const ScriptType> val) const { }
[[nodiscard]] virtual bool CanBeIterated() const;
[[nodiscard]] virtual shared_ptr<const ScriptType> GetIteratorKeyType() const;
@ -104,6 +114,8 @@ namespace Porygon{
}
[[nodiscard]] CastResult CastableTo(const shared_ptr<const ScriptType>& 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<const StringScriptType> Dynamic;
@ -134,7 +146,7 @@ namespace Porygon{
return !(num->IsAwareOfFloat() && num->IsFloat());
}
inline shared_ptr<const ScriptType> GetIndexedType(const ScriptType* indexer) const final{
inline shared_ptr<const ScriptType> GetIndexedType(shared_ptr<const ScriptType> 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<const ScriptType> _valueType;
// Consider adding a check whether the table actually contains a type if every key is static.
public:
explicit NumericalTableScriptType(shared_ptr<const ScriptType> 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<const NumericScriptType*>(indexer);
return !(num->IsAwareOfFloat() && num->IsFloat());
}
inline shared_ptr<const ScriptType> GetIndexedType(const ScriptType* indexer) const final{
return _valueType;
}
[[nodiscard]]
inline bool CanBeIterated() const final{
return true;
}
[[nodiscard]]
inline shared_ptr<const ScriptType> GetIteratorKeyType() const final{
return NumericScriptType::AwareInt;
}
[[nodiscard]] bool IsCountable() const override {
return true;
}
};
}

View File

@ -2,72 +2,165 @@
#ifndef PORYGONLANG_TABLESCRIPTTYPE_HPP
#define PORYGONLANG_TABLESCRIPTTYPE_HPP
#include <unordered_map>
#include <utility>
#include "../Binder/BoundVariables/BoundVariable.hpp"
#include "../Exception.hpp"
namespace Porygon{
class TableScriptType : public ScriptType{
const map<Utilities::HashedString, BoundVariable*>* _values;
const int _localVariableCount;
enum TableType{
Unknown,
Numerical,
StringKeyed,
Dictionary
};
bool _isContentAware;
TableType _tableType;
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:
explicit TableScriptType(map<Utilities::HashedString, BoundVariable*>* 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<const ScriptType> 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<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;
}
[[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 = _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<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;
}
[[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(_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<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();
_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<const ScriptType> GetIndexedType(const ScriptType* indexer) const final{
auto stringKey = dynamic_cast<const StringScriptType*>(indexer);
if (stringKey != nullptr && stringKey->IsKnownAtBind() && _values != nullptr){
return _values-> at(Utilities::HashedString::CreateLookup(stringKey->GetHashValue()))->GetType();
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}
};
}
return make_shared<ScriptType>(TypeClass::Any);
}
[[nodiscard]] inline shared_ptr<const ScriptType> GetIndexedType(uint32_t hash) const final{
return _values-> at(Utilities::HashedString::CreateLookup(hash))->GetType();
}
[[nodiscard]] inline const map<Utilities::HashedString, BoundVariable*>* GetValues() const{
return _values;
}
[[nodiscard]]
bool CanBeIterated() const final {
return true;
}
[[nodiscard]]
shared_ptr<const ScriptType> GetIteratorKeyType() const final {
return make_shared<ScriptType>(TypeClass::Any);
}
bool IsCountable() const override {
return true;
}
};
}

View File

@ -51,7 +51,7 @@ namespace Porygon::UserData {
return indexer->operator==(_keyType);
}
[[nodiscard]] shared_ptr<const ScriptType> GetIndexedType(const ScriptType* indexer) const final{
[[nodiscard]] shared_ptr<const ScriptType> GetIndexedType(shared_ptr<const ScriptType> indexer) const final{
return _valueType;
}
@ -70,6 +70,15 @@ namespace Porygon::UserData {
[[nodiscard]] bool IsCountable() const override {
return true;
}
[[nodiscard]]
bool CanSetIndexValue(shared_ptr<const ScriptType> indexer, shared_ptr<const ScriptType> val) const override {
if (indexer->CastableTo(_keyType, false) == CastResult::InvalidCast)
return false;
if (val->CastableTo(_valueType, false) == CastResult::InvalidCast)
return false;
return true;
}
};
}

View File

@ -12,11 +12,11 @@ namespace Porygon::UserData{
: GenericFunctionOption(std::move(returnType), std::move(parameterTypes)) {
}
static UserDataFunctionOption* FromRawPointers(const ScriptType* returnType, vector<const ScriptType*> parameterTypes){
static UserDataFunctionOption* FromRawPointers(ScriptType* returnType, vector<ScriptType*> parameterTypes){
auto rt = shared_ptr<const ScriptType>(returnType);
auto p = vector<shared_ptr<const ScriptType>>(parameterTypes.size());
for (size_t i = 0; i < parameterTypes.size(); i++){
p[i] = shared_ptr<const ScriptType>(parameterTypes[i]);
p[i] = shared_ptr<ScriptType>(parameterTypes[i]);
}
return new UserDataFunctionOption(rt, p);
}

View File

@ -36,7 +36,7 @@ namespace Porygon::UserData {
auto str = dynamic_cast<const StringScriptType*>(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<const ScriptType> GetIndexedType(const ScriptType *indexer) const final {
auto stringKey = dynamic_cast<const StringScriptType*>(indexer);
shared_ptr<const ScriptType> GetIndexedType(shared_ptr<const ScriptType> indexer) const final {
auto stringKey = dynamic_pointer_cast<const StringScriptType>(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<const ScriptType> indexer, shared_ptr<const ScriptType> val) const override {
if (indexer->GetClass() != TypeClass::String)
return false;
auto s = dynamic_pointer_cast<const StringScriptType>(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<const ScriptType> 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);
}
};
}

View File

@ -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