From 4a034bc051eedbff46808b4411722122c69fe94b Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Fri, 24 May 2019 19:14:30 +0200 Subject: [PATCH] Reworked evaluation to use internal type instead of boost::any --- .idea/misc.xml | 1 + src/Evaluator/BinaryEvaluation.cpp | 88 +++++-------------- src/Evaluator/EvalValues/EvalValue.hpp | 28 ++++++ src/Evaluator/EvalValues/NumericEvalValue.cpp | 50 +++++++++++ src/Evaluator/EvalValues/NumericEvalValue.hpp | 65 ++++++++++++++ src/Evaluator/Evaluator.cpp | 57 +++--------- src/Evaluator/Evaluator.hpp | 17 ++-- src/Script.cpp | 2 + src/Script.hpp | 5 +- .../integration/NumericalOperationsTests.cpp | 16 ++-- 10 files changed, 197 insertions(+), 132 deletions(-) create mode 100644 src/Evaluator/EvalValues/EvalValue.hpp create mode 100644 src/Evaluator/EvalValues/NumericEvalValue.cpp create mode 100644 src/Evaluator/EvalValues/NumericEvalValue.hpp diff --git a/.idea/misc.xml b/.idea/misc.xml index d959e79..6631fb7 100755 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -4,6 +4,7 @@ + diff --git a/src/Evaluator/BinaryEvaluation.cpp b/src/Evaluator/BinaryEvaluation.cpp index 2812ea1..7a723c6 100644 --- a/src/Evaluator/BinaryEvaluation.cpp +++ b/src/Evaluator/BinaryEvaluation.cpp @@ -2,76 +2,30 @@ #include "../Script.hpp" #include "EvaluationException.hpp" #include "Evaluator.hpp" +#include "EvalValues/NumericEvalValue.hpp" -long Evaluator::EvaluateIntegerBinary(BoundBinaryExpression *expression) { - long leftValue = this -> EvaluateIntegerExpression(expression->GetLeft()); - long rightValue = this -> EvaluateIntegerExpression(expression->GetRight()); +NumericEvalValue* Evaluator::EvaluateIntegerBinary(BoundBinaryExpression *expression) { + NumericEvalValue* leftValue = this -> EvaluateIntegerExpression(expression->GetLeft()); + NumericEvalValue* rightValue = this -> EvaluateIntegerExpression(expression->GetRight()); + NumericEvalValue* result; switch (expression->GetOperation()){ - case BoundBinaryOperation ::Addition: return leftValue + rightValue; - case BoundBinaryOperation ::Subtraction: return leftValue - rightValue; - case BoundBinaryOperation ::Multiplication: return leftValue * rightValue; - case BoundBinaryOperation ::Division: return leftValue / rightValue; - + case BoundBinaryOperation ::Addition: + result = leftValue -> operator+ (rightValue); + break; + case BoundBinaryOperation::Subtraction: + result = leftValue -> operator- (rightValue); + break; + case BoundBinaryOperation::Multiplication: + result = leftValue -> operator* (rightValue); + break; + case BoundBinaryOperation::Division: + result = leftValue -> operator/ (rightValue); + break; default: - throw EvaluationException("Can't evaluate operation to integer"); - } -} - -double EvaluateBinaryOperation(double l, double r, BoundBinaryOperation op){ - switch (op){ - case BoundBinaryOperation ::Addition: return l + r; - case BoundBinaryOperation ::Subtraction: return l - r; - case BoundBinaryOperation ::Multiplication: return l * r; - case BoundBinaryOperation ::Division: return l / r; - - default: - throw EvaluationException("Can't evaluate operation to float"); - } -} - -double EvaluateBinaryOperation(double l, long r, BoundBinaryOperation op){ - switch (op){ - case BoundBinaryOperation ::Addition: return l + r; - case BoundBinaryOperation ::Subtraction: return l - r; - case BoundBinaryOperation ::Multiplication: return l * r; - case BoundBinaryOperation ::Division: return l / r; - - default: - throw EvaluationException("Can't evaluate operation to float"); - } -} - -double EvaluateBinaryOperation(long l, double r, BoundBinaryOperation op){ - switch (op){ - case BoundBinaryOperation ::Addition: return l + r; - case BoundBinaryOperation ::Subtraction: return l - r; - case BoundBinaryOperation ::Multiplication: return l * r; - case BoundBinaryOperation ::Division: return l / r; - - default: - throw EvaluationException("Can't evaluate operation to float"); - } -} - -double Evaluator::EvaluateFloatBinary(BoundBinaryExpression *expression) { - auto left = expression->GetLeft(); - auto right = expression->GetRight(); - auto leftType = (NumericScriptType*)left->GetType(); - auto rightType = (NumericScriptType*)right->GetType(); - if (leftType->IsFloat()){ - double leftValue = this -> EvaluateFloatExpression(left); - if (rightType->IsFloat()){ - double rightValue = this -> EvaluateFloatExpression(right); - return EvaluateBinaryOperation(leftValue, rightValue, expression->GetOperation()); - } else{ - long rightValue = this -> EvaluateIntegerExpression(right); - return EvaluateBinaryOperation(leftValue, rightValue, expression->GetOperation()); - } - } else{ - long leftValue = this-> EvaluateIntegerExpression(left); - // If the left is an integer, we know the right must be a float, otherwise we'd be evaluating as integer; - double rightValue = this -> EvaluateFloatExpression(right); - return EvaluateBinaryOperation(leftValue, rightValue, expression->GetOperation()); + throw EvaluationException("Can't evaluate operation to numeric"); } + delete leftValue; + delete rightValue; + return result; } \ No newline at end of file diff --git a/src/Evaluator/EvalValues/EvalValue.hpp b/src/Evaluator/EvalValues/EvalValue.hpp new file mode 100644 index 0000000..36e1d40 --- /dev/null +++ b/src/Evaluator/EvalValues/EvalValue.hpp @@ -0,0 +1,28 @@ + +#ifndef PORYGONLANG_EVALVALUE_HPP +#define PORYGONLANG_EVALVALUE_HPP + +#include "../../ScriptType.hpp" +#include "../EvaluationException.hpp" +#include + +class EvalValue{ +public: + virtual ~EvalValue() = default; + virtual ScriptType* GetType() = 0; + + virtual long EvaluateInteger(){ + throw EvaluationException("Can't evaluate this EvalValue as integer."); + } + virtual double EvaluateFloat(){ + throw EvaluationException("Can't evaluate this EvalValue as float."); + } + virtual bool EvaluateBool(){ + throw EvaluationException("Can't evaluate this EvalValue as bool."); + } + virtual std::string EvaluateString(){ + throw EvaluationException("Can't evaluate this EvalValue as string."); + } +}; + +#endif //PORYGONLANG_EVALVALUE_HPP diff --git a/src/Evaluator/EvalValues/NumericEvalValue.cpp b/src/Evaluator/EvalValues/NumericEvalValue.cpp new file mode 100644 index 0000000..d387d04 --- /dev/null +++ b/src/Evaluator/EvalValues/NumericEvalValue.cpp @@ -0,0 +1,50 @@ + +#include "NumericEvalValue.hpp" + +NumericEvalValue *NumericEvalValue::operator+(NumericEvalValue *b) { + if (this->IsFloat() && b->IsFloat()){ + return new FloatEvalValue(this->GetFloatValue() + b->GetFloatValue()); + } else if (this->IsFloat()){ + return new FloatEvalValue(this->GetFloatValue() + b->GetIntegerValue()); + } else if (b->IsFloat()){ + return new FloatEvalValue(this->GetIntegerValue() + b->GetFloatValue()); + } else{ + return new IntegerEvalValue(this->GetIntegerValue() + b->GetIntegerValue()); + } +} + +NumericEvalValue *NumericEvalValue::operator-(NumericEvalValue *b) { + if (this->IsFloat() && b->IsFloat()){ + return new FloatEvalValue(this->GetFloatValue() - b->GetFloatValue()); + } else if (this->IsFloat()){ + return new FloatEvalValue(this->GetFloatValue() - b->GetIntegerValue()); + } else if (b->IsFloat()){ + return new FloatEvalValue(this->GetIntegerValue() - b->GetFloatValue()); + } else{ + return new IntegerEvalValue(this->GetIntegerValue() - b->GetIntegerValue()); + } +} + +NumericEvalValue *NumericEvalValue::operator*(NumericEvalValue *b) { + if (this->IsFloat() && b->IsFloat()){ + return new FloatEvalValue(this->GetFloatValue() * b->GetFloatValue()); + } else if (this->IsFloat()){ + return new FloatEvalValue(this->GetFloatValue() * b->GetIntegerValue()); + } else if (b->IsFloat()){ + return new FloatEvalValue(this->GetIntegerValue() * b->GetFloatValue()); + } else{ + return new IntegerEvalValue(this->GetIntegerValue() * b->GetIntegerValue()); + } +} + +NumericEvalValue *NumericEvalValue::operator/(NumericEvalValue *b) { + if (this->IsFloat() && b->IsFloat()){ + return new FloatEvalValue(this->GetFloatValue() / b->GetFloatValue()); + } else if (this->IsFloat()){ + return new FloatEvalValue(this->GetFloatValue() / b->GetIntegerValue()); + } else if (b->IsFloat()){ + return new FloatEvalValue(this->GetIntegerValue() / b->GetFloatValue()); + } else{ + return new IntegerEvalValue(this->GetIntegerValue() / b->GetIntegerValue()); + } +} diff --git a/src/Evaluator/EvalValues/NumericEvalValue.hpp b/src/Evaluator/EvalValues/NumericEvalValue.hpp new file mode 100644 index 0000000..c8f7053 --- /dev/null +++ b/src/Evaluator/EvalValues/NumericEvalValue.hpp @@ -0,0 +1,65 @@ + +#ifndef PORYGONLANG_NUMERICEVALVALUE_HPP +#define PORYGONLANG_NUMERICEVALVALUE_HPP + +#include "EvalValue.hpp" + +class NumericEvalValue : public EvalValue{ + + virtual long GetIntegerValue() = 0; + virtual double GetFloatValue() = 0; + +protected: + ScriptType* _type; +public: + ~NumericEvalValue() override{ + delete _type; + }; + virtual const bool IsFloat() = 0; + ScriptType* GetType() override { + return _type; + } + + NumericEvalValue* operator +(NumericEvalValue* b); + NumericEvalValue* operator -(NumericEvalValue* b); + NumericEvalValue* operator *(NumericEvalValue* b); + NumericEvalValue* operator /(NumericEvalValue* b); +}; + +class IntegerEvalValue : public NumericEvalValue{ + long _value; + long GetIntegerValue() final{return _value;} + double GetFloatValue() final{ throw EvaluationException("Attempting to retrieve float from int eval value."); } +public: + explicit IntegerEvalValue(long value){ + _type = new NumericScriptType(true, false); + _value = value; + } + const bool IsFloat() final{ + return false; + } + + long EvaluateInteger() final{ + return _value; + } +}; + +class FloatEvalValue : public NumericEvalValue{ + double _value; + long GetIntegerValue() final{ throw EvaluationException("Attempting to retrieve float from int eval value."); } + double GetFloatValue() final{return _value;} +public: + explicit FloatEvalValue(double value){ + _type = new NumericScriptType(true, true); + _value = value; + } + const bool IsFloat() final{ + return true; + } + + double EvaluateFloat() final{ + return _value; + } +}; + +#endif //PORYGONLANG_NUMERICEVALVALUE_HPP diff --git a/src/Evaluator/Evaluator.cpp b/src/Evaluator/Evaluator.cpp index 1eda38f..3885b18 100644 --- a/src/Evaluator/Evaluator.cpp +++ b/src/Evaluator/Evaluator.cpp @@ -25,40 +25,24 @@ void Evaluator::EvaluateExpressionStatement(BoundExpressionStatement *statement) this->_scriptData->_lastValue = this -> EvaluateExpression(statement->GetExpression()); } -any *Evaluator::EvaluateExpression(BoundExpression *expression) { +EvalValue *Evaluator::EvaluateExpression(BoundExpression *expression) { auto type = expression -> GetType(); switch (type->GetClass()){ - case TypeClass ::Number: - { - auto numType = (NumericScriptType*)type; - if (numType->IsAwareOfFloat()){ - if (numType->IsFloat()){ - double d = this -> EvaluateFloatExpression(expression); - return new boost::any(d); - } else{ - long l = this -> EvaluateIntegerExpression(expression); - return new boost::any(l); - } - } - break; - } + case TypeClass ::Number: return this -> EvaluateIntegerExpression(expression); + default: throw; } } -long Evaluator::EvaluateIntegerExpression(BoundExpression *expression) { +NumericEvalValue* Evaluator::EvaluateIntegerExpression(BoundExpression *expression) { auto exprType = expression->GetType(); if (exprType->GetClass() != TypeClass::Number){ throw EvaluationException("Can't evaluate expression as integer, it will not return a number."); } - auto numType = (NumericScriptType*)exprType; - if (numType->IsAwareOfFloat() && numType->IsFloat()){ - throw EvaluationException("Can't evaluate expression as integer, it will return a float, not an integer."); - } switch (expression->GetKind()){ - case BoundExpressionKind ::LiteralInteger: return ((BoundLiteralIntegerExpression*)expression)->GetValue(); + case BoundExpressionKind ::LiteralInteger: return new IntegerEvalValue(((BoundLiteralIntegerExpression*)expression)->GetValue()); + case BoundExpressionKind ::LiteralFloat: return new FloatEvalValue(((BoundLiteralFloatExpression*)expression)->GetValue()); case BoundExpressionKind ::Binary: return this -> EvaluateIntegerBinary((BoundBinaryExpression*)expression); - case BoundExpressionKind ::LiteralFloat: case BoundExpressionKind ::LiteralString: case BoundExpressionKind ::LiteralBool: case BoundExpressionKind ::Bad: @@ -66,32 +50,11 @@ long Evaluator::EvaluateIntegerExpression(BoundExpression *expression) { } } -double Evaluator::EvaluateFloatExpression(BoundExpression *expression) { - auto exprType = expression->GetType(); - if (exprType->GetClass() != TypeClass::Number){ - throw EvaluationException("Can't evaluate expression as float, it will not return a number."); - } - auto numType = (NumericScriptType*)exprType; - if (numType->IsAwareOfFloat() && !numType->IsFloat()){ - throw EvaluationException("Can't evaluate expression as integer, it will return an integer, not a float."); - } - switch (expression->GetKind()){ - case BoundExpressionKind ::LiteralFloat: return ((BoundLiteralFloatExpression*)expression)->GetValue(); - case BoundExpressionKind ::Binary: return this -> EvaluateFloatBinary((BoundBinaryExpression*)expression); - - case BoundExpressionKind ::LiteralInteger: - case BoundExpressionKind ::LiteralString: - case BoundExpressionKind ::LiteralBool: - case BoundExpressionKind ::Bad: - throw; - } +EvalValue* Evaluator::EvaluateBoolExpression(BoundExpression *expression) { + return nullptr; } -bool Evaluator::EvaluateBoolExpression(BoundExpression *expression) { - return false; -} - -std::string Evaluator::EvaluateStringExpression(BoundExpression *expression) { - return std::__cxx11::string(); +EvalValue* Evaluator::EvaluateStringExpression(BoundExpression *expression) { + return nullptr; } diff --git a/src/Evaluator/Evaluator.hpp b/src/Evaluator/Evaluator.hpp index 6f6e193..a14a556 100644 --- a/src/Evaluator/Evaluator.hpp +++ b/src/Evaluator/Evaluator.hpp @@ -6,11 +6,14 @@ #include #include "../Binder/BoundStatements/BoundStatement.hpp" #include "../Script.hpp" +#include "EvalValues/EvalValue.hpp" +#include "EvalValues/NumericEvalValue.hpp" + using namespace boost; class Evaluator { - any* _result; + EvalValue* _result; Script* _scriptData; @@ -18,14 +21,12 @@ class Evaluator { void EvaluateBlockStatement(BoundBlockStatement* statement); void EvaluateExpressionStatement(BoundExpressionStatement* statement); - any* EvaluateExpression(BoundExpression* expression); - long EvaluateIntegerExpression(BoundExpression* expression); - double EvaluateFloatExpression(BoundExpression* expression); - bool EvaluateBoolExpression(BoundExpression* expression); - std::string EvaluateStringExpression(BoundExpression* expression); + EvalValue* EvaluateExpression(BoundExpression* expression); + NumericEvalValue* EvaluateIntegerExpression(BoundExpression* expression); + EvalValue* EvaluateBoolExpression(BoundExpression* expression); + EvalValue* EvaluateStringExpression(BoundExpression* expression); - long EvaluateIntegerBinary(BoundBinaryExpression* expression); - double EvaluateFloatBinary(BoundBinaryExpression *expression); + NumericEvalValue* EvaluateIntegerBinary(BoundBinaryExpression* expression); public: Evaluator(Script* script){ _scriptData = script; diff --git a/src/Script.cpp b/src/Script.cpp index a130a1f..4d32d97 100644 --- a/src/Script.cpp +++ b/src/Script.cpp @@ -24,6 +24,8 @@ void Script::Evaluate() { Script::~Script() { delete this -> Diagnostics; delete this -> BoundScript; + delete this -> _lastValue; + delete this -> _evaluator; } void Script::Parse(string script) { diff --git a/src/Script.hpp b/src/Script.hpp index de80f39..4ce2052 100644 --- a/src/Script.hpp +++ b/src/Script.hpp @@ -11,13 +11,14 @@ class Script; class Evaluator; #include "Evaluator/Evaluator.hpp" +#include "Evaluator/EvalValues/EvalValue.hpp" using namespace std; class Script { friend class Evaluator; - boost::any* _lastValue; + EvalValue* _lastValue; Evaluator* _evaluator; @@ -33,7 +34,7 @@ public: void Evaluate(); - boost::any* GetLastValue(){ + EvalValue* GetLastValue(){ return _lastValue; }; }; diff --git a/tests/integration/NumericalOperationsTests.cpp b/tests/integration/NumericalOperationsTests.cpp index 48609c0..57dc208 100644 --- a/tests/integration/NumericalOperationsTests.cpp +++ b/tests/integration/NumericalOperationsTests.cpp @@ -7,28 +7,28 @@ TEST_CASE( "Integer Addition", "[integration]" ) { REQUIRE(!script.Diagnostics -> HasErrors()); script.Evaluate(); auto lastValue = script.GetLastValue(); - REQUIRE(*any_cast(lastValue) == 6); + REQUIRE(lastValue->EvaluateInteger() == 6); } TEST_CASE( "Integer Subtraction", "[integration]" ) { Script script = Script::Create("1 - 5"); REQUIRE(!script.Diagnostics -> HasErrors()); script.Evaluate(); auto lastValue = script.GetLastValue(); - REQUIRE(*any_cast(lastValue) == -4); + REQUIRE(lastValue->EvaluateInteger() == -4); } TEST_CASE( "Integer Multiplication", "[integration]" ) { Script script = Script::Create("5 * 8"); REQUIRE(!script.Diagnostics -> HasErrors()); script.Evaluate(); auto lastValue = script.GetLastValue(); - REQUIRE(*any_cast(lastValue) == 40); + REQUIRE(lastValue->EvaluateInteger() == 40); } TEST_CASE( "Integer Division", "[integration]" ) { Script script = Script::Create("40 / 8"); REQUIRE(!script.Diagnostics -> HasErrors()); script.Evaluate(); auto lastValue = script.GetLastValue(); - REQUIRE(*any_cast(lastValue) == 5); + REQUIRE(lastValue->EvaluateInteger() == 5); } TEST_CASE( "Float Addition", "[integration]" ) { @@ -36,27 +36,27 @@ TEST_CASE( "Float Addition", "[integration]" ) { REQUIRE(!script.Diagnostics -> HasErrors()); script.Evaluate(); auto lastValue = script.GetLastValue(); - REQUIRE(*any_cast(lastValue) == 6.54); + REQUIRE(lastValue->EvaluateFloat() == 6.54); } TEST_CASE( "Float Subtraction", "[integration]" ) { Script script = Script::Create("1.8 - 5.14"); REQUIRE(!script.Diagnostics -> HasErrors()); script.Evaluate(); auto lastValue = script.GetLastValue(); - REQUIRE(*any_cast(lastValue) == -3.34); + REQUIRE(lastValue->EvaluateFloat() == -3.34); } TEST_CASE( "Float Multiplication", "[integration]" ) { Script script = Script::Create("5.2 * 8.9"); REQUIRE(!script.Diagnostics -> HasErrors()); script.Evaluate(); auto lastValue = script.GetLastValue(); - REQUIRE(*any_cast(lastValue) == 46.28); + REQUIRE(lastValue->EvaluateFloat() == 46.28); } TEST_CASE( "Float Division", "[integration]" ) { Script script = Script::Create("95.18 / 8.87"); REQUIRE(!script.Diagnostics -> HasErrors()); script.Evaluate(); auto lastValue = script.GetLastValue(); - REQUIRE(*any_cast(lastValue) == Approx(10.7305524239)); + REQUIRE(lastValue->EvaluateFloat() == Approx(10.7305524239)); } #endif