Work on userdata binary operations
continuous-integration/drone/push Build encountered an error Details

This commit is contained in:
Deukhoofd 2019-09-08 13:53:24 +02:00
parent 85936f3d68
commit eca0c6b075
Signed by: Deukhoofd
GPG Key ID: ADF2E9256009EDCE
8 changed files with 136 additions and 49 deletions

View File

@ -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<const UserData::UserDataScriptType>(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) {

View File

@ -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<const ScriptType> 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;

View File

@ -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<const BoundUserdataBinaryExpression*>(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<const UserData::UserDataValue*>(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);

View File

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

View File

@ -6,6 +6,7 @@
#include <mutex>
#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<UserDataBinaryOperation*> _addition = {};
std::vector<UserDataBinaryOperation*> _subtraction = {};
std::vector<UserDataBinaryOperation*> _multiplication = {};
std::vector<UserDataBinaryOperation*> _division = {};
std::vector<UserDataBinaryOperation*> _equality = {};
std::vector<UserDataBinaryOperation*> _inequality = {};
std::vector<UserDataBinaryOperation*> _lessThan = {};
std::vector<UserDataBinaryOperation*> _lessThanEquals = {};
std::vector<UserDataBinaryOperation*> _greaterThan = {};
std::vector<UserDataBinaryOperation*> _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<UserDataBinaryOperation*>& v, const shared_ptr<const ScriptType>& 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<const ScriptType>& 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();
}
}
};

View File

@ -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<const ScriptType> _secondParameter;
const shared_ptr<const ScriptType> _returnType;
public:
UserDataBinaryOperation(void *parent,
Evaluation::EvalValue *(*func)(void *, Evaluation::EvalValue *),
UserDataBinaryOperation(Evaluation::EvalValue *(*func)(void *, const Evaluation::EvalValue *),
shared_ptr<ScriptType> secondParameter,
shared_ptr<ScriptType> 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<const ScriptType>& v){
if (v->operator==(_secondParameter)){
return true;
}
return v->CastableTo(_secondParameter, true) != CastResult::InvalidCast;
}
[[nodiscard]]

View File

@ -71,6 +71,7 @@ namespace Porygon::UserData {
s << ScriptType::ToString() << " (" << _userData->Get()->GetIdentifier()->GetDebugString() << ")";
return s.str();
}
};
}

View File

@ -74,7 +74,7 @@ namespace Porygon::UserData {
delete value;
}
inline void* GetObjectPointer(){
inline void* GetObjectPointer() const{
return _obj;
}