From 996b5be49635209e6d42079f501ed4786cbd29b2 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Fri, 14 Jun 2019 14:59:38 +0200 Subject: [PATCH] Implements basics for UserData --- src/Binder/Binder.cpp | 3 +- src/Evaluator/Evaluator.cpp | 9 ++++++ src/Evaluator/Evaluator.hpp | 1 + src/UserData/UserData.cpp | 2 ++ src/UserData/UserData.hpp | 25 +++++++++++++++ src/UserData/UserDataField.cpp | 2 ++ src/UserData/UserDataField.hpp | 33 +++++++++++++++++++ src/UserData/UserDataScriptType.cpp | 2 ++ src/UserData/UserDataScriptType.hpp | 31 ++++++++++++++++++ src/UserData/UserDataStorage.cpp | 4 +++ src/UserData/UserDataStorage.hpp | 21 ++++++++++++ src/UserData/UserDataValue.cpp | 2 ++ src/UserData/UserDataValue.hpp | 50 +++++++++++++++++++++++++++++ tests/integration/UserData.cpp | 48 +++++++++++++++++++++++++++ 14 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 src/UserData/UserData.cpp create mode 100644 src/UserData/UserData.hpp create mode 100644 src/UserData/UserDataField.cpp create mode 100644 src/UserData/UserDataField.hpp create mode 100644 src/UserData/UserDataScriptType.cpp create mode 100644 src/UserData/UserDataScriptType.hpp create mode 100644 src/UserData/UserDataStorage.cpp create mode 100644 src/UserData/UserDataStorage.hpp create mode 100644 src/UserData/UserDataValue.cpp create mode 100644 src/UserData/UserDataValue.hpp create mode 100644 tests/integration/UserData.cpp diff --git a/src/Binder/Binder.cpp b/src/Binder/Binder.cpp index cf3056c..2d4968b 100644 --- a/src/Binder/Binder.cpp +++ b/src/Binder/Binder.cpp @@ -3,6 +3,7 @@ #include "Binder.hpp" #include "../TableScriptType.hpp" #include "BoundExpressions/BoundTableExpression.hpp" +#include "../UserData/UserDataScriptType.hpp" #include BoundScriptStatement *Binder::Bind(Script* script, const ParsedScriptStatement *s, BoundScope* scriptScope) { @@ -74,7 +75,7 @@ std::shared_ptr ParseTypeIdentifier(HashedString s){ case HashedString::ConstHash("number"): return std::make_shared(false, false); case HashedString::ConstHash("bool"): return std::make_shared(TypeClass::Bool); case HashedString::ConstHash("string"): return std::make_shared(false, 0); - default: return std::make_shared(TypeClass::Error); // todo: change to userdata + default: return std::make_shared(s.GetHash()); } } diff --git a/src/Evaluator/Evaluator.cpp b/src/Evaluator/Evaluator.cpp index 056f3b7..d54a742 100644 --- a/src/Evaluator/Evaluator.cpp +++ b/src/Evaluator/Evaluator.cpp @@ -102,6 +102,7 @@ shared_ptr Evaluator::EvaluateExpression(const BoundExpression *expre case TypeClass ::Function: return this->EvaluateFunctionExpression(expression); case TypeClass ::Nil: return this->EvaluateNilExpression(expression); case TypeClass ::Table: return this-> EvaluateTableExpression(expression); + case TypeClass ::UserData: return this -> EvaluateUserDataExpression(expression); default: throw; } } @@ -291,3 +292,11 @@ shared_ptr Evaluator::EvaluateComplexTableExpression(const BoundExpre this -> _evaluationScope = currentEvaluator; return make_shared(variables); } + +shared_ptr Evaluator::EvaluateUserDataExpression(const BoundExpression *expression) { + switch (expression->GetKind()){ + case BoundExpressionKind ::Variable: return this->GetVariable((BoundVariableExpression*)expression); + case BoundExpressionKind ::Index: return this -> EvaluateIndexExpression(expression); + default: throw; + } +} diff --git a/src/Evaluator/Evaluator.hpp b/src/Evaluator/Evaluator.hpp index d106586..fcf9956 100644 --- a/src/Evaluator/Evaluator.hpp +++ b/src/Evaluator/Evaluator.hpp @@ -48,6 +48,7 @@ class Evaluator { shared_ptr EvaluateIndexExpression(const BoundExpression* expression); shared_ptr EvaluateNumericTableExpression(const BoundExpression* expression); shared_ptr EvaluateComplexTableExpression(const BoundExpression *expression); + shared_ptr EvaluateUserDataExpression(const BoundExpression *expression); shared_ptr GetVariable(const BoundVariableExpression *expression); public: diff --git a/src/UserData/UserData.cpp b/src/UserData/UserData.cpp new file mode 100644 index 0000000..4130941 --- /dev/null +++ b/src/UserData/UserData.cpp @@ -0,0 +1,2 @@ + +#include "UserData.hpp" diff --git a/src/UserData/UserData.hpp b/src/UserData/UserData.hpp new file mode 100644 index 0000000..e78d248 --- /dev/null +++ b/src/UserData/UserData.hpp @@ -0,0 +1,25 @@ +#ifndef PORYGONLANG_USERDATA_HPP +#define PORYGONLANG_USERDATA_HPP + +#include +#include +#include "UserDataField.hpp" + +class UserData { + std::unordered_map _fields; +public: + explicit UserData(std::unordered_map fields){ + _fields = std::move(fields); + } + + bool ContainsField(int fieldId){ + return _fields.find(fieldId) != _fields.end(); + } + + UserDataField* GetField(int fieldId){ + return _fields[fieldId]; + } +}; + + +#endif //PORYGONLANG_USERDATA_HPP diff --git a/src/UserData/UserDataField.cpp b/src/UserData/UserDataField.cpp new file mode 100644 index 0000000..b01fafc --- /dev/null +++ b/src/UserData/UserDataField.cpp @@ -0,0 +1,2 @@ + +#include "UserDataField.hpp" diff --git a/src/UserData/UserDataField.hpp b/src/UserData/UserDataField.hpp new file mode 100644 index 0000000..1409e72 --- /dev/null +++ b/src/UserData/UserDataField.hpp @@ -0,0 +1,33 @@ + +#ifndef PORYGONLANG_USERDATAFIELD_HPP +#define PORYGONLANG_USERDATAFIELD_HPP + + +#include "../Evaluator/EvalValues/EvalValue.hpp" + +class UserDataField { + shared_ptr _type; + EvalValue* (*_get)(void* obj); + void (*_set)(void* obj, EvalValue*); +public: + UserDataField(ScriptType* type, EvalValue* (*getter)(void* obj), void (*setter)(void* obj, EvalValue*)){ + _type = shared_ptr(type); + _get = getter; + _set = setter; + } + + shared_ptr GetType(){ + return _type; + } + + EvalValue* Get(void* obj){ + return this ->_get(obj); + } + + void Set(void* obj, EvalValue* val){ + this->_set(obj, val); + } +}; + + +#endif //PORYGONLANG_USERDATAFIELD_HPP diff --git a/src/UserData/UserDataScriptType.cpp b/src/UserData/UserDataScriptType.cpp new file mode 100644 index 0000000..27f872d --- /dev/null +++ b/src/UserData/UserDataScriptType.cpp @@ -0,0 +1,2 @@ + +#include "UserDataScriptType.hpp" diff --git a/src/UserData/UserDataScriptType.hpp b/src/UserData/UserDataScriptType.hpp new file mode 100644 index 0000000..7907e95 --- /dev/null +++ b/src/UserData/UserDataScriptType.hpp @@ -0,0 +1,31 @@ + +#ifndef PORYGONLANG_USERDATASCRIPTTYPE_HPP +#define PORYGONLANG_USERDATASCRIPTTYPE_HPP + + +#include "../ScriptType.hpp" +#include "UserData.hpp" +#include "UserDataStorage.hpp" + +class UserDataScriptType : public ScriptType{ + UserData* _userData; +public: + explicit UserDataScriptType(int id) : ScriptType(TypeClass::UserData){ + _userData = UserDataStorage::GetUserDataType(id); + } + + bool CanBeIndexedWith(ScriptType* indexer) final{ + return indexer->GetClass() == TypeClass ::String; + } + + shared_ptr GetIndexedType(ScriptType* indexer) final{ + auto stringKey = (StringScriptType*)indexer; + if (stringKey->IsKnownAtBind()){ + return _userData->GetField(stringKey->GetHashValue())->GetType(); + } + throw "TODO: indexing with dynamic keys"; + } +}; + + +#endif //PORYGONLANG_USERDATASCRIPTTYPE_HPP diff --git a/src/UserData/UserDataStorage.cpp b/src/UserData/UserDataStorage.cpp new file mode 100644 index 0000000..4f3b6df --- /dev/null +++ b/src/UserData/UserDataStorage.cpp @@ -0,0 +1,4 @@ + +#include "UserDataStorage.hpp" + +std::unordered_map UserDataStorage::_userData = {}; \ No newline at end of file diff --git a/src/UserData/UserDataStorage.hpp b/src/UserData/UserDataStorage.hpp new file mode 100644 index 0000000..3e826b6 --- /dev/null +++ b/src/UserData/UserDataStorage.hpp @@ -0,0 +1,21 @@ + +#ifndef PORYGONLANG_USERDATASTORAGE_HPP +#define PORYGONLANG_USERDATASTORAGE_HPP + +#include +#include "UserData.hpp" + +class UserDataStorage { + static std::unordered_map _userData; +public: + static void RegisterType(int i, UserData* ud){ + UserDataStorage::_userData.insert({i, ud}); + } + + static UserData* GetUserDataType(int i){ + return UserDataStorage::_userData[i]; + } +}; + + +#endif //PORYGONLANG_USERDATASTORAGE_HPP diff --git a/src/UserData/UserDataValue.cpp b/src/UserData/UserDataValue.cpp new file mode 100644 index 0000000..1dfa6b6 --- /dev/null +++ b/src/UserData/UserDataValue.cpp @@ -0,0 +1,2 @@ + +#include "UserDataValue.hpp" diff --git a/src/UserData/UserDataValue.hpp b/src/UserData/UserDataValue.hpp new file mode 100644 index 0000000..1185f24 --- /dev/null +++ b/src/UserData/UserDataValue.hpp @@ -0,0 +1,50 @@ + +#ifndef PORYGONLANG_USERDATAVALUE_HPP +#define PORYGONLANG_USERDATAVALUE_HPP + + +#include "../Evaluator/EvalValues/EvalValue.hpp" +#include "UserData.hpp" +#include "UserDataStorage.hpp" + +class UserDataValue : public EvalValue{ + UserData* _userData; + void* _obj; +public: + UserDataValue(UserData* userData, void* obj){ + _userData = userData; + _obj = obj; + } + + UserDataValue(int userDataId, void* obj){ + _userData = UserDataStorage::GetUserDataType(userDataId); + _obj = obj; + } + + const TypeClass GetTypeClass() final{ + return TypeClass ::UserData; + } + + bool operator ==(EvalValue* b) final { + if (b->GetTypeClass() != TypeClass::UserData) + return false; + return _obj == ((UserDataValue*)b)->_obj; + } + + shared_ptr Clone() final{ + return make_shared(_userData, _obj); + } + + std::size_t GetHashCode() final{ + return reinterpret_cast(_obj); + } + + shared_ptr IndexValue(EvalValue* val) final { + auto fieldId = val->GetHashCode(); + auto field = _userData->GetField(fieldId); + return shared_ptr(field->Get(_obj)); + } +}; + + +#endif //PORYGONLANG_USERDATAVALUE_HPP diff --git a/tests/integration/UserData.cpp b/tests/integration/UserData.cpp new file mode 100644 index 0000000..87e8548 --- /dev/null +++ b/tests/integration/UserData.cpp @@ -0,0 +1,48 @@ + +#ifdef TESTS_BUILD +#include +#include "../src/Script.hpp" +#include "../../src/UserData/UserData.hpp" +#include "../../src/UserData/UserDataStorage.hpp" +#include "../../src/UserData/UserDataValue.hpp" + +class UserDataTestObject{ +public: + int foo = 10; + + static EvalValue* GetFoo(void* obj){ + return new IntegerEvalValue(((UserDataTestObject*)obj)->foo); + } + + static void SetFoo(void* obj, EvalValue* val){ + ((UserDataTestObject*)obj)->foo = val->EvaluateInteger(); + } + + static UserData* CreateData(){ + return new UserData({ + { + HashedString::ConstHash("foo"), + new UserDataField(new NumericScriptType(true, false), GetFoo, SetFoo) + } + }); + } +}; + +TEST_CASE( "Gets UserData value", "[integration]" ) { + UserDataStorage::RegisterType(HashedString::ConstHash("testObject"), UserDataTestObject::CreateData()); + Script* script = Script::Create(R"( +function testFunc(testObject obj) + return obj["foo"] +end +)"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto parameter = new UserDataValue(HashedString::ConstHash("testObject"), new UserDataTestObject()); + auto variable = script->CallFunction("testFunc", {parameter}); + REQUIRE(variable != nullptr); + REQUIRE(variable->EvaluateInteger() == 10); + delete script; +} + + +#endif