Reworked evaluation to use internal type instead of boost::any
This commit is contained in:
parent
fed4c65bef
commit
4a034bc051
|
@ -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" />
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue