Implements handling of userdata collection items
continuous-integration/drone/push Build was killed Details

This commit is contained in:
Deukhoofd 2019-07-28 19:01:07 +02:00
parent bbcebffefd
commit 4b5672e3f5
Signed by: Deukhoofd
GPG Key ID: ADF2E9256009EDCE
6 changed files with 223 additions and 2 deletions

View File

@ -0,0 +1 @@
#include "UserDataCollectionType.hpp"

View File

@ -0,0 +1,61 @@
#ifndef PORYGONLANG_USERDATACOLLECTIONTYPE_HPP
#define PORYGONLANG_USERDATACOLLECTIONTYPE_HPP
#include <utility>
#include "../ScriptTypes/ScriptType.hpp"
namespace Porygon::UserData {
class UserDataCollectionType : public ScriptType {
shared_ptr<const ScriptType> _keyType;
shared_ptr<const ScriptType> _valueType;
const bool _indexable;
const bool _iterable;
public:
UserDataCollectionType(shared_ptr<const ScriptType> keyType, shared_ptr<const ScriptType> valueType,
bool indexable, bool iterable)
: ScriptType(TypeClass::Table),
_keyType(std::move(keyType)),
_valueType(std::move(valueType)),
_indexable(indexable),
_iterable(iterable)
{}
static shared_ptr<UserDataCollectionType> CreateIndexable(const shared_ptr<const ScriptType>& keyType, const shared_ptr<const ScriptType>& valueType){
return make_shared<UserDataCollectionType>(keyType, valueType, true, true);
}
static UserDataCollectionType* CreateIndexable(const ScriptType* keyType, const ScriptType* valueType){
return new UserDataCollectionType(shared_ptr<const ScriptType>(keyType),
shared_ptr<const ScriptType>(valueType), true, true);
}
static shared_ptr<UserDataCollectionType> CreateIterable(const shared_ptr<const ScriptType>& valueType){
return make_shared<UserDataCollectionType>(nullptr, valueType, false, true);
}
bool CanBeIndexedWith(const ScriptType* indexer) const final{
if (!_indexable){
return false;
}
return indexer->operator==(_keyType.get());
}
[[nodiscard]] shared_ptr<const ScriptType> GetIndexedType(const ScriptType* indexer) const final{
return _valueType;
}
[[nodiscard]] bool CanBeIterated() const final{
return _iterable;
}
[[nodiscard]] shared_ptr<const ScriptType> GetIteratorKeyType() const final{
if (_indexable){
return _keyType;
} else{
return _valueType;
}
}
};
}
#endif //PORYGONLANG_USERDATACOLLECTIONTYPE_HPP

View File

@ -0,0 +1 @@
#include "UserDataCollectionValue.hpp"

View File

@ -0,0 +1,75 @@
#ifndef PORYGONLANG_USERDATACOLLECTIONVALUE_HPP
#define PORYGONLANG_USERDATACOLLECTIONVALUE_HPP
#include <utility>
#include "UserDataCollectionType.hpp"
#include "../Evaluator/EvalValues/EvalValue.hpp"
#include "../Utilities/Random.hpp"
namespace Porygon::UserData {
class UserDataCollectionHelper{
void* _parentObject;
const EvalValue* (*_get)(void*, const EvalValue*);
void (*_set)(void*, const EvalValue* , const EvalValue*);
public:
UserDataCollectionHelper(void* parentObject,
const EvalValue* (*get)(void*, const EvalValue*),
void (*set)(void*, const EvalValue*, const EvalValue*))
: _parentObject(parentObject), _get(get), _set(set){}
const EvalValue* Get(const EvalValue* key) const{
return _get(_parentObject, key);
}
void Set(const EvalValue* key, const EvalValue* value) const{
_set(_parentObject, key, value);
}
};
class UserDataCollectionValue : public Evaluation::EvalValue{
shared_ptr<UserDataCollectionType> _type;
shared_ptr<const UserDataCollectionHelper> _helper;
const size_t _hash;
UserDataCollectionValue(shared_ptr<UserDataCollectionType> type,
shared_ptr<const UserDataCollectionHelper> helper, size_t hash)
: _type(std::move(type)), _helper(std::move(helper)), _hash(hash)
{
}
public:
UserDataCollectionValue(ScriptType* type, const UserDataCollectionHelper* helper)
: _type((UserDataCollectionType*)type), _helper(helper), _hash(Utilities::Random::Get())
{
}
[[nodiscard]] TypeClass GetTypeClass() const final{
return TypeClass ::Table;
}
bool operator==(const EvalValue *b) const final{
return b->GetHashCode() == _hash;
}
[[nodiscard]] EvalValue* Clone() const final{
return new UserDataCollectionValue(_type, _helper, _hash);
}
[[nodiscard]] std::size_t GetHashCode() const final{
return _hash;
}
const EvalValue* IndexValue(const EvalValue *val) const final{
return _helper->Get(val);
}
void SetIndexValue(const EvalValue *key, const EvalValue* value) const final{
_helper->Set(key, value);
}
};
}
#endif //PORYGONLANG_USERDATACOLLECTIONVALUE_HPP

View File

@ -28,6 +28,8 @@
#define PORYGON_INTEGER_TYPE ((Porygon::ScriptType*)new Porygon::NumericScriptType(true, false))
#define PORYGON_FLOAT_TYPE ((Porygon::ScriptType*)new Porygon::NumericScriptType(true, true))
#define PORYGON_STRING_TYPE ((Porygon::ScriptType*)new Porygon::StringScriptType(false, 0))
#define PORYGON_INDEXABLE_TYPE(keyType, valueType) \
((Porygon::ScriptType*)Porygon::UserData::UserDataCollectionType::CreateIndexable(keyType, valueType))
#define PORYGON_FIELD(fieldName, fieldType, getterHelper, setterHelper) \
{ \
@ -42,7 +44,7 @@
{ \
Porygon::Utilities::HashedString::ConstHash(#fieldName), \
new Porygon::UserData::UserDataField(fieldType, \
[](void* obj) -> Porygon::Evaluation::EvalValue* { return new getterHelper;}, \
[](void* obj) -> const Porygon::Evaluation::EvalValue* { return new getterHelper;}, \
nullptr \
) \
}, \
@ -63,6 +65,30 @@
PORYGON_READONLY_FIELD(fieldName, PORYGON_FLOAT_TYPE, \
Porygon::EvaluationFloatEvalValue(((T_USERDATA*)obj)->fieldName))
/*
#define PORYGON_INDEXABLE_FIELD(fieldName, keyType, valueType) \
PORYGON_FIELD(fieldName, PORYGON_INDEXABLE_TYPE(keyType, valueType), \
const Porygon::Evaluation::IntegerEvalValue(((T_USERDATA*)obj)->fieldName), val->EvaluateInteger())
*/
#define PORYGON_READONLY_VECTOR_FIELD(fieldName, valueType) \
PORYGON_READONLY_FIELD(fieldName, PORYGON_INDEXABLE_TYPE(PORYGON_INTEGER_TYPE, valueType), \
Porygon::UserData::UserDataCollectionValue( \
PORYGON_INDEXABLE_TYPE(PORYGON_INTEGER_TYPE, valueType), \
new UserDataCollectionHelper( \
obj, \
[](void* obj, const EvalValue* v) -> const EvalValue*{ \
auto index = v->EvaluateInteger() - 1; \
auto val = ((T_USERDATA*)obj)->fieldName;\
return EvalValueHelper::Create(val[index]); \
} \
, [](void* obj, const EvalValue* key, const EvalValue* value){ \
auto index = key->EvaluateInteger() - 1;\
((T_USERDATA*)obj)->fieldName[index] = value->EvaluateInteger(); \
}) \
) \
)
#define PORYGON_FUNCTION(fieldName, returnType, ...) \
{ \
@ -73,7 +99,8 @@
\
\
[](void* obj) -> const Porygon::Evaluation::EvalValue* { \
auto t = new Porygon::Evaluation::GenericFunctionEvalValue(make_shared<GenericFunctionScriptType>(), rand()); \
auto t = new Porygon::Evaluation::GenericFunctionEvalValue(make_shared<GenericFunctionScriptType>(), \
Porygon::Utilities::Random::Get()); \
t->RegisterOption(new Porygon::UserData::UserDataFunction( \
[](void* obj, const Porygon::Evaluation::EvalValue* par[], int parameterCount) \
-> const Porygon::Evaluation::EvalValue*{return ((const T_USERDATA*)obj)->invoke__##fieldName(obj, par, parameterCount);}, \

View File

@ -8,7 +8,10 @@
#include "../../src/UserData/UserDataFunction.hpp"
#include "../../src/UserData/UserDataFunctionType.hpp"
#include "../../src/UserData/UserDataTemplates.hpp"
#include "../../src/UserData/UserDataCollectionType.hpp"
#include "../../src/UserData/UserDataCollectionValue.hpp"
#include "../../src/Evaluator/EvalValues/EvalValueHelper.hpp"
#include "../../src/Utilities/Random.hpp"
using namespace Porygon;
using namespace Porygon::UserData;
@ -17,6 +20,7 @@ using namespace Porygon::Utilities;
class UserDataTestObject{
public:
int foo = 10;
vector<int> fooVector = {5,10,15,25};
int getFoo(){
return foo;
}
@ -29,11 +33,17 @@ public:
private:
PORYGON_PREPARE_FUNCTION(UserDataTestObject, getFoo, IntegerEvalValue)
PORYGON_PREPARE_FUNCTION(UserDataTestObject, Addition, IntegerEvalValue, (par[0] -> EvaluateInteger()), (par[1] -> EvaluateInteger()))
void __setFooVector(const EvalValue* key, const EvalValue* value){
auto index = key->EvaluateInteger();
fooVector[index] = value->EvaluateInteger();
}
public:
PORYGON_USERDATA(UserDataTestObject,
PORYGON_INTEGER_FIELD(foo)
PORYGON_INTEGER_FUNCTION(getFoo)
PORYGON_INTEGER_FUNCTION(Addition, PORYGON_INTEGER_TYPE, PORYGON_INTEGER_TYPE)
PORYGON_READONLY_VECTOR_FIELD(fooVector, PORYGON_INTEGER_TYPE)
)
};
@ -117,5 +127,51 @@ end
UserDataStorage::ClearTypes();
}
TEST_CASE( "Gets userdata vector value", "[integration]" ) {
UserDataStorage::RegisterType(HashedString::ConstHash("testObject"), UserDataTestObject::__createUserData());
Script* script = Script::Create(R"(
function testFunc(testObject obj)
return obj.fooVector[1]
end
)");
REQUIRE(!script->Diagnostics -> HasErrors());
script->Evaluate();
auto func = (GenericFunctionEvalValue*)script -> GetVariable(u"testFunc");
auto funcType = func -> GetType();
REQUIRE(funcType->GetFirstOption()->GetReturnType()->GetClass() == TypeClass::Number);
auto obj = new UserDataTestObject();
auto parameter = new UserDataValue(HashedString::ConstHash("testObject"), obj);
auto result = script->CallFunction(u"testFunc", {parameter});
REQUIRE(result -> EvaluateInteger() == 5);
delete obj;
delete parameter;
delete result;
delete script;
delete func;
UserDataStorage::ClearTypes();
}
TEST_CASE( "Sets userdata vector value", "[integration]" ) {
UserDataStorage::RegisterType(HashedString::ConstHash("testObject"), UserDataTestObject::__createUserData());
Script* script = Script::Create(R"(
function testFunc(testObject obj)
obj.fooVector[3] = 684
end
)");
REQUIRE(!script->Diagnostics -> HasErrors());
script->Evaluate();
auto func = (GenericFunctionEvalValue*)script -> GetVariable(u"testFunc");
auto funcType = func -> GetType();
auto obj = new UserDataTestObject();
auto parameter = new UserDataValue(HashedString::ConstHash("testObject"), obj);
script->CallFunction(u"testFunc", {parameter});
REQUIRE(obj->fooVector[2] == 684);
delete obj;
delete parameter;
delete script;
delete func;
UserDataStorage::ClearTypes();
}
#endif