Work on evaluation
This commit is contained in:
parent
57cd3efec9
commit
d949d9aa8f
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
#include "EvaluationException.hpp"
|
||||
#include "Evaluator.hpp"
|
||||
|
|
@ -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
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue