Work on evaluation

This commit is contained in:
Deukhoofd 2019-05-23 18:50:09 +02:00
parent 57cd3efec9
commit d949d9aa8f
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
10 changed files with 283 additions and 4 deletions

View File

@ -15,4 +15,13 @@ add_executable(PorygonLangTests
target_compile_definitions(PorygonLangTests PRIVATE TESTS_BUILD)
find_package( Boost )
include_directories(
${BOOST_INCLUDE_DIRS}
)
target_link_libraries(PorygonLang ${Boost_LIBRARIES} )
target_link_libraries(PorygonLangTests ${Boost_LIBRARIES} )
include(CTest)

View File

@ -20,7 +20,6 @@ enum class BoundExpressionKind{
Unary,
Binary,
Parenthesized,
};
class BoundExpression{
@ -150,6 +149,18 @@ public:
BoundExpressionKind GetKind() final{
return BoundExpressionKind ::Binary;
}
BoundExpression* GetLeft(){
return _left;
}
BoundExpression* GetRight(){
return _right;
}
BoundBinaryOperation GetOperation(){
return _operation;
}
};
class BoundUnaryExpression : public BoundExpression {

View File

@ -37,6 +37,10 @@ public:
BoundStatementKind GetKind() override{
return BoundStatementKind ::Block;
}
vector<BoundStatement*> GetStatements(){
return _statements;
}
};
class BoundScriptStatement : public BoundBlockStatement{
@ -62,6 +66,10 @@ public:
BoundStatementKind GetKind() final{
return BoundStatementKind ::Expression;
}
BoundExpression* GetExpression(){
return _expression;
}
};
#endif //PORYGONLANG_BOUNDSTATEMENT_HPP

View File

@ -0,0 +1,4 @@
#include "EvaluationException.hpp"
#include "Evaluator.hpp"

View File

@ -0,0 +1,22 @@
#ifndef PORYGONLANG_EVALUATIONEXCEPTION_HPP
#define PORYGONLANG_EVALUATIONEXCEPTION_HPP
#include <exception>
#include <string>
using namespace std;
class EvaluationException : std::exception {
string _message;
public:
explicit EvaluationException(string message){
_message = message;
}
const string defaultErrorText = "An evaluation exception occurred: ";
const char* what() const noexcept final{
return (defaultErrorText + _message).c_str();
}
};
#endif //PORYGONLANG_EVALUATIONEXCEPTION_HPP

151
src/Evaluator/Evaluator.cpp Normal file
View File

@ -0,0 +1,151 @@
#include "Evaluator.hpp"
#include "EvaluationException.hpp"
#include "BinaryEvaluation.cpp"
#include "../Script.hpp"
void Evaluator::Evaluate(BoundScriptStatement *statement) {
EvaluateBlockStatement(statement);
}
void Evaluator::EvaluateStatement(BoundStatement *statement) {
switch (statement->GetKind()){
case BoundStatementKind ::Script: throw; // Should never happen
case BoundStatementKind ::Block: return this -> EvaluateBlockStatement((BoundBlockStatement*)statement);
case BoundStatementKind ::Expression: return this -> EvaluateExpressionStatement((BoundExpressionStatement*)statement);
}
}
void Evaluator::EvaluateBlockStatement(BoundBlockStatement* statement) {
for (auto s: statement->GetStatements()){
this -> EvaluateStatement(s);
}
}
void Evaluator::EvaluateExpressionStatement(BoundExpressionStatement *statement) {
this->_scriptData->_lastValue = this -> EvaluateExpression(statement->GetExpression());
}
any *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;
}
}
}
long 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 ::Binary: return this -> EvaluateIntegerBinary((BoundBinaryExpression*)expression);
case BoundExpressionKind ::LiteralFloat:
case BoundExpressionKind ::LiteralString:
case BoundExpressionKind ::LiteralBool:
case BoundExpressionKind ::Bad:
throw;
}
}
double Evaluator::EvaluateFloatExpression(BoundExpression *expression) {
return 0;
}
bool Evaluator::EvaluateBoolExpression(BoundExpression *expression) {
return false;
}
std::string Evaluator::EvaluateStringExpression(BoundExpression *expression) {
return std::__cxx11::string();
}
long Evaluator::EvaluateIntegerBinary(BoundBinaryExpression *expression) {
long leftValue = this -> EvaluateIntegerExpression(expression->GetLeft());
long rightValue = this -> EvaluateIntegerExpression(expression->GetRight());
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;
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());
}
}

View File

@ -0,0 +1,39 @@
#ifndef PORYGONLANG_EVALUATOR_HPP
#define PORYGONLANG_EVALUATOR_HPP
#include <string>
#include <boost/any.hpp>
#include "../Binder/BoundStatements/BoundStatement.hpp"
#include "../Script.hpp"
using namespace boost;
class Evaluator {
any* _result;
Script* _scriptData;
void EvaluateStatement(BoundStatement* statement);
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);
long EvaluateIntegerBinary(BoundBinaryExpression* expression);
double EvaluateFloatBinary(BoundBinaryExpression *expression);
public:
Evaluator(Script* script){
_scriptData = script;
}
void Evaluate(BoundScriptStatement* statement);
};
#endif //PORYGONLANG_EVALUATOR_HPP

View File

@ -12,6 +12,15 @@ Script Script::Create(string script) {
return s;
}
Script::Script() {
Diagnostics = new class Diagnostics();
_evaluator = new Evaluator(this);
}
void Script::Evaluate() {
_evaluator->Evaluate(BoundScript);
}
Script::~Script() {
delete this -> Diagnostics;
delete this -> BoundScript;

View File

@ -5,15 +5,23 @@
#define PORYGONLANG_SCRIPT_HPP
#include <string>
#include <boost/any.hpp>
#include "Diagnostics/Diagnostics.hpp"
#include "Binder/BoundStatements/BoundStatement.hpp"
class Script;
class Evaluator;
#include "Evaluator/Evaluator.hpp"
using namespace std;
class Script {
explicit Script(){
Diagnostics = new class Diagnostics();
};
friend class Evaluator;
boost::any* _lastValue;
Evaluator* _evaluator;
explicit Script();
void Parse(string script);
BoundScriptStatement* BoundScript;
@ -22,6 +30,12 @@ public:
Diagnostics* Diagnostics;
~Script();
void Evaluate();
boost::any* GetLastValue(){
return _lastValue;
};
};

View File

@ -0,0 +1,12 @@
#ifdef TESTS_BUILD
#include <catch.hpp>
#include "../src/Script.hpp"
TEST_CASE( "Simple addition", "[integration]" ) {
Script script = Script::Create("1 + 5");
REQUIRE(!script.Diagnostics -> HasErrors());
script.Evaluate();
auto lastValue = script.GetLastValue();
REQUIRE(*any_cast<long>(lastValue) == 6);
}
#endif