Reworked evaluation to use internal type instead of boost::any

This commit is contained in:
Deukhoofd 2019-05-24 19:14:30 +02:00
parent fed4c65bef
commit 4a034bc051
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
10 changed files with 197 additions and 132 deletions

View File

@ -4,6 +4,7 @@
<component name="CidrRootsConfiguration">
<sourceRoots>
<file path="$PROJECT_DIR$/src" />
<file path="$PROJECT_DIR$/tests" />
</sourceRoots>
<libraryRoots>
<file path="$PROJECT_DIR$/extern" />

View File

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

View File

@ -0,0 +1,28 @@
#ifndef PORYGONLANG_EVALVALUE_HPP
#define PORYGONLANG_EVALVALUE_HPP
#include "../../ScriptType.hpp"
#include "../EvaluationException.hpp"
#include <string>
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

View File

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

View File

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

View File

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

View File

@ -6,11 +6,14 @@
#include <boost/any.hpp>
#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;

View File

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

View File

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

View File

@ -7,28 +7,28 @@ TEST_CASE( "Integer Addition", "[integration]" ) {
REQUIRE(!script.Diagnostics -> HasErrors());
script.Evaluate();
auto lastValue = script.GetLastValue();
REQUIRE(*any_cast<long>(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<long>(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<long>(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<long>(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<double>(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<double>(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<double>(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<double>(lastValue) == Approx(10.7305524239));
REQUIRE(lastValue->EvaluateFloat() == Approx(10.7305524239));
}
#endif