diff --git a/src/Binder/Binder.cpp b/src/Binder/Binder.cpp index 8ccab07..82fbe47 100644 --- a/src/Binder/Binder.cpp +++ b/src/Binder/Binder.cpp @@ -420,6 +420,19 @@ namespace Porygon::Binder { auto boundLeftType = boundLeft->GetType(); auto boundRightType = boundRight->GetType(); + if (boundLeftType->GetClass() == TypeClass::UserData){ + auto ud = dynamic_pointer_cast(boundLeftType); + auto op = ud->GetUserData()->Get()->GetBinaryOperation(expression->GetOperatorKind(), boundRightType); + if (op == nullptr){ + this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::NoBinaryOperationFound, + expression->GetStartPosition(), + expression->GetLength()); + return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength()); + } + return new BoundUserdataBinaryExpression(boundLeft, boundRight, op, op->GetReturnType(), + expression->GetStartPosition(), expression->GetLength()); + } + switch (expression->GetOperatorKind()) { case BinaryOperatorKind::Addition: if (boundLeftType->GetClass() == TypeClass::Number && boundRightType->GetClass() == TypeClass::Number) { diff --git a/src/Binder/BoundExpressions/BoundExpression.hpp b/src/Binder/BoundExpressions/BoundExpression.hpp index 3f7ffd7..de816a5 100644 --- a/src/Binder/BoundExpressions/BoundExpression.hpp +++ b/src/Binder/BoundExpressions/BoundExpression.hpp @@ -8,6 +8,7 @@ #include "../BoundOperators.hpp" #include "../BoundVariables/BoundVariableKey.hpp" #include "../../Utilities/StringUtils.hpp" +#include "../../UserData/UserDataOperation.hpp" using namespace std; @@ -24,6 +25,7 @@ namespace Porygon::Binder { Unary, Binary, + UserdataBinary, FunctionCall, Index, PeriodIndex, @@ -304,6 +306,39 @@ namespace Porygon::Binder { } }; + class BoundUserdataBinaryExpression : public BoundExpression{ + private: + const BoundExpression* _left; + const BoundExpression* _right; + const UserData::UserDataBinaryOperation* _operation; + public: + BoundUserdataBinaryExpression(BoundExpression *left, BoundExpression *right, UserData::UserDataBinaryOperation* op, + shared_ptr result, + unsigned int start, unsigned int length) + : BoundExpression(start, length, std::move(result)), + _left(left), + _right(right), + _operation(op) {} + + [[nodiscard]] inline const BoundExpression* GetLeft() const { return _left; } + [[nodiscard]] inline const BoundExpression* GetRight() const { return _right; } + [[nodiscard]] inline const UserData::UserDataBinaryOperation* GetOperation() const { return _operation; } + + [[nodiscard]] + inline BoundExpressionKind GetKind() const final { + return BoundExpressionKind::UserdataBinary; + } + + void GetTreeString(std::stringstream& stream, size_t indents) const final { + DrawIndents(stream, indents); + stream << "BinaryExpression: " << "Userdata operand " + << " (" << GetType()->ToString() << ")" << endl; + _left->GetTreeString(stream, indents + 1); + stream << endl; + _right->GetTreeString(stream, indents + 1); + } + }; + class BoundUnaryExpression : public BoundExpression { const BoundExpression *_operand; const BoundUnaryOperation _operation; diff --git a/src/Evaluator/Evaluator.cpp b/src/Evaluator/Evaluator.cpp index c70e723..df1e33d 100644 --- a/src/Evaluator/Evaluator.cpp +++ b/src/Evaluator/Evaluator.cpp @@ -12,6 +12,7 @@ #include "../ScriptTypes/TableScriptType.hpp" #include "../UserData/UserDataFunction.hpp" #include "EvalValues/NumericalTableEvalValue.hpp" +#include "../UserData/UserDataValue.hpp" using namespace std; using namespace Porygon::Binder; @@ -248,6 +249,8 @@ namespace Porygon::Evaluation { return this->EvaluateUnary((BoundUnaryExpression *) expression); case BoundExpressionKind::Binary: return this->EvaluateBinary((BoundBinaryExpression *) expression); + case BoundExpressionKind ::UserdataBinary: + return this->EvaluateUserDataBinary(dynamic_cast(expression)); case BoundExpressionKind::FunctionCall: return this->EvaluateFunctionCallExpression(expression); case BoundExpressionKind::Index: @@ -282,6 +285,15 @@ namespace Porygon::Evaluation { return leftValue->BinaryOperation(operation, rightValue.Get()); } + EvalValuePointer Evaluator::EvaluateUserDataBinary(const BoundUserdataBinaryExpression *expression) { + auto leftValue = this->EvaluateExpression(expression->GetLeft()); + auto rightValue = this->EvaluateExpression(expression->GetRight()); + auto op = expression->GetOperation(); + auto o = dynamic_cast(leftValue.Get()); + auto val = op->Invoke(o->GetObjectPointer(), rightValue.Get()); + return val; + } + EvalValuePointer Evaluator::EvaluateUnary(const BoundUnaryExpression *expression) { auto exp = expression->GetOperand(); auto val = EvaluateExpression(exp); diff --git a/src/Evaluator/Evaluator.hpp b/src/Evaluator/Evaluator.hpp index b64fac5..b072f85 100644 --- a/src/Evaluator/Evaluator.hpp +++ b/src/Evaluator/Evaluator.hpp @@ -39,6 +39,7 @@ namespace Porygon::Evaluation{ EvalValuePointer EvaluateExpression(const BoundExpression *expression); EvalValuePointer EvaluateBinary(const BoundBinaryExpression *expression); + EvalValuePointer EvaluateUserDataBinary(const BoundUserdataBinaryExpression *expression); EvalValuePointer EvaluateUnary(const BoundUnaryExpression *expression); EvalValuePointer EvaluateFunctionCallExpression(const BoundExpression *expression); diff --git a/src/UserData/UserData.hpp b/src/UserData/UserData.hpp index 86ff499..e566f86 100644 --- a/src/UserData/UserData.hpp +++ b/src/UserData/UserData.hpp @@ -6,6 +6,7 @@ #include #include "UserDataField.hpp" #include "UserDataOperation.hpp" +#include "../Parser/BinaryOperatorKind.hpp" namespace Porygon::UserData { class UserData { @@ -14,19 +15,16 @@ namespace Porygon::UserData { std::mutex _mutex; // Binary operations - UserDataBinaryOperation* _addition = nullptr; - UserDataBinaryOperation* _subtraction = nullptr; - UserDataBinaryOperation* _multiplication = nullptr; - UserDataBinaryOperation* _division = nullptr; - UserDataBinaryOperation* _equality = nullptr; - UserDataBinaryOperation* _inequality = nullptr; - UserDataBinaryOperation* _lessThen = nullptr; - UserDataBinaryOperation* _lessThenEqual = nullptr; - UserDataBinaryOperation* _greaterThen = nullptr; - UserDataBinaryOperation* _greaterThenEqual = nullptr; - UserDataBinaryOperation* _logicalAnd = nullptr; - UserDataBinaryOperation* _logicalOr = nullptr; - UserDataBinaryOperation* _concatenation = nullptr; + std::vector _addition = {}; + std::vector _subtraction = {}; + std::vector _multiplication = {}; + std::vector _division = {}; + std::vector _equality = {}; + std::vector _inequality = {}; + std::vector _lessThan = {}; + std::vector _lessThanEquals = {}; + std::vector _greaterThan = {}; + std::vector _greaterThanEquals = {}; bool (*_isCastable)(const ScriptType* type, bool explicitCast); Evaluation::EvalValue* (*_cast)(void* obj, const ScriptType* castType); @@ -42,20 +40,16 @@ namespace Porygon::UserData { ~UserData(){ _fields.clear(); - - delete _addition; - delete _subtraction; - delete _multiplication; - delete _division; - delete _equality; - delete _inequality; - delete _lessThen; - delete _lessThenEqual; - delete _greaterThen; - delete _greaterThenEqual; - delete _logicalAnd; - delete _logicalOr; - delete _concatenation; + for (auto o: _addition) delete o; + for (auto o: _subtraction) delete o; + for (auto o: _multiplication) delete o; + for (auto o: _division) delete o; + for (auto o: _equality) delete o; + for (auto o: _inequality) delete o; + for (auto o: _lessThan) delete o; + for (auto o: _lessThanEquals) delete o; + for (auto o: _greaterThan) delete o; + for (auto o: _greaterThanEquals) delete o; delete _hashedString; } @@ -101,23 +95,49 @@ namespace Porygon::UserData { return _cast(obj, castType); } + void AddBinaryOperation(Binder::BoundBinaryOperation kind, UserDataBinaryOperation* op){ + switch (kind){ + + case Binder::BoundBinaryOperation::Addition: _addition.push_back(op); + case Binder::BoundBinaryOperation::Subtraction: _subtraction.push_back(op); + case Binder::BoundBinaryOperation::Multiplication: _multiplication.push_back(op); + case Binder::BoundBinaryOperation::Division: _division.push_back(op); + case Binder::BoundBinaryOperation::Equality: _equality.push_back(op); + case Binder::BoundBinaryOperation::Inequality: _inequality.push_back(op); + case Binder::BoundBinaryOperation::LessThan: _lessThan.push_back(op); + case Binder::BoundBinaryOperation::LessThanEquals: _lessThanEquals.push_back(op); + case Binder::BoundBinaryOperation::GreaterThan: _greaterThan.push_back(op); + case Binder::BoundBinaryOperation::GreaterThanEquals: _greaterThanEquals.push_back(op); + default: throw exception(); + } + } + + private: + static UserDataBinaryOperation* ResolveBinaryOperation(const vector& v, const shared_ptr& b){ + for (auto o: v){ + if (o->IsValid(b)){ + return o; + } + } + return nullptr; + } + + public: [[nodiscard]] - UserDataBinaryOperation* GetBinaryOperation(Binder::BoundBinaryOperation op){ + UserDataBinaryOperation* GetBinaryOperation(Parser::BinaryOperatorKind op, const shared_ptr& b){ switch (op){ - case Binder::BoundBinaryOperation::Addition: return _addition; - case Binder::BoundBinaryOperation::Subtraction: return _subtraction; - case Binder::BoundBinaryOperation::Multiplication: return _multiplication; - case Binder::BoundBinaryOperation::Division: return _division; - case Binder::BoundBinaryOperation::Equality: return _equality; - case Binder::BoundBinaryOperation::Inequality: return _inequality; - case Binder::BoundBinaryOperation::LessThan: return _lessThen; - case Binder::BoundBinaryOperation::LessThanEquals: return _lessThenEqual; - case Binder::BoundBinaryOperation::GreaterThan: return _greaterThen; - case Binder::BoundBinaryOperation::GreaterThanEquals: return _greaterThenEqual; - case Binder::BoundBinaryOperation::LogicalAnd: return _logicalAnd; - case Binder::BoundBinaryOperation::LogicalOr: return _logicalOr; - case Binder::BoundBinaryOperation::Concatenation: return _concatenation; + case Parser::BinaryOperatorKind::Addition: return ResolveBinaryOperation(_addition, b); + case Parser::BinaryOperatorKind::Subtraction: return ResolveBinaryOperation(_subtraction, b); + case Parser::BinaryOperatorKind::Multiplication: return ResolveBinaryOperation(_multiplication, b); + case Parser::BinaryOperatorKind::Division: return ResolveBinaryOperation(_division, b); + case Parser::BinaryOperatorKind::Equality: return ResolveBinaryOperation(_equality, b); + case Parser::BinaryOperatorKind::Inequality: return ResolveBinaryOperation(_inequality, b); + case Parser::BinaryOperatorKind::Less: return ResolveBinaryOperation(_lessThan, b); + case Parser::BinaryOperatorKind::LessOrEquals: return ResolveBinaryOperation(_lessThanEquals, b); + case Parser::BinaryOperatorKind::Greater: return ResolveBinaryOperation(_greaterThan, b); + case Parser::BinaryOperatorKind::GreaterOrEquals: return ResolveBinaryOperation(_greaterThanEquals, b); + default: throw exception(); } } }; diff --git a/src/UserData/UserDataOperation.hpp b/src/UserData/UserDataOperation.hpp index 63fa39f..7f0c5c0 100644 --- a/src/UserData/UserDataOperation.hpp +++ b/src/UserData/UserDataOperation.hpp @@ -7,20 +7,25 @@ namespace Porygon::UserData { class UserDataBinaryOperation { - void* _parent; - Evaluation::EvalValue *(*_func)(void *obj, Evaluation::EvalValue *b); + Evaluation::EvalValue *(*_func)(void *obj, const Evaluation::EvalValue *b); const shared_ptr _secondParameter; const shared_ptr _returnType; public: - UserDataBinaryOperation(void *parent, - Evaluation::EvalValue *(*func)(void *, Evaluation::EvalValue *), + UserDataBinaryOperation(Evaluation::EvalValue *(*func)(void *, const Evaluation::EvalValue *), shared_ptr secondParameter, shared_ptr returnType) - : _parent(parent), _func(func), _secondParameter(std::move(secondParameter)), + : _func(func), _secondParameter(std::move(secondParameter)), _returnType(std::move(returnType)) {} - Evaluation::EvalValue* Invoke(Evaluation::EvalValue * b) const{ - return _func(_parent, b); + Evaluation::EvalValue* Invoke(void* a, const Evaluation::EvalValue * b) const{ + return _func(a, b); + } + + bool IsValid(const shared_ptr& v){ + if (v->operator==(_secondParameter)){ + return true; + } + return v->CastableTo(_secondParameter, true) != CastResult::InvalidCast; } [[nodiscard]] diff --git a/src/UserData/UserDataScriptType.hpp b/src/UserData/UserDataScriptType.hpp index dc22f19..4f727b1 100644 --- a/src/UserData/UserDataScriptType.hpp +++ b/src/UserData/UserDataScriptType.hpp @@ -71,6 +71,7 @@ namespace Porygon::UserData { s << ScriptType::ToString() << " (" << _userData->Get()->GetIdentifier()->GetDebugString() << ")"; return s.str(); } + }; } diff --git a/src/UserData/UserDataValue.hpp b/src/UserData/UserDataValue.hpp index acb276a..1f785cf 100644 --- a/src/UserData/UserDataValue.hpp +++ b/src/UserData/UserDataValue.hpp @@ -74,7 +74,7 @@ namespace Porygon::UserData { delete value; } - inline void* GetObjectPointer(){ + inline void* GetObjectPointer() const{ return _obj; }