From 0205b92ae6be5de546a87325203aa451f1746ca0 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sat, 25 May 2019 16:15:20 +0200 Subject: [PATCH] Implements string evaluation and concat --- src/Binder/Binder.cpp | 4 +- src/Evaluator/BinaryEvaluation.cpp | 14 +++++++ src/Evaluator/EvalValues/EvalValue.hpp | 7 ++++ src/Evaluator/EvalValues/NumericEvalValue.hpp | 13 +++++++ src/Evaluator/EvalValues/StringEvalValue.cpp | 2 + src/Evaluator/EvalValues/StringEvalValue.hpp | 38 +++++++++++++++++++ src/Evaluator/Evaluator.cpp | 20 ++++++++-- src/Evaluator/Evaluator.hpp | 4 +- src/ScriptType.hpp | 2 +- tests/integration/StringOperationsTests.cpp | 25 ++++++++++++ 10 files changed, 123 insertions(+), 6 deletions(-) create mode 100644 src/Evaluator/EvalValues/StringEvalValue.cpp create mode 100644 src/Evaluator/EvalValues/StringEvalValue.hpp create mode 100644 tests/integration/StringOperationsTests.cpp diff --git a/src/Binder/Binder.cpp b/src/Binder/Binder.cpp index f2a3389..1965ace 100644 --- a/src/Binder/Binder.cpp +++ b/src/Binder/Binder.cpp @@ -79,8 +79,10 @@ BoundExpression* Binder::BindBinaryOperator(BinaryExpression* expression){ return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Addition, new NumericScriptType(false, false), expression->GetStartPosition(), expression->GetLength()); } + } else if (boundLeftType->GetClass() == TypeClass::String){ + return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Concatenation, new ScriptType(TypeClass::String), + expression->GetStartPosition(), expression->GetLength()); } - //TODO: String Concatenation break; case BinaryOperatorKind ::Subtraction: if (boundLeftType->GetClass() == TypeClass::Number && boundRightType->GetClass() == TypeClass::Number){ diff --git a/src/Evaluator/BinaryEvaluation.cpp b/src/Evaluator/BinaryEvaluation.cpp index 73ad493..9d3263f 100644 --- a/src/Evaluator/BinaryEvaluation.cpp +++ b/src/Evaluator/BinaryEvaluation.cpp @@ -3,6 +3,7 @@ #include "EvaluationException.hpp" #include "Evaluator.hpp" #include "EvalValues/NumericEvalValue.hpp" +#include "EvalValues/StringEvalValue.hpp" NumericEvalValue* Evaluator::EvaluateIntegerBinary(BoundBinaryExpression *expression) { NumericEvalValue* leftValue = this -> EvaluateIntegerExpression(expression->GetLeft()); @@ -71,4 +72,17 @@ BooleanEvalValue* Evaluator::EvaluateBooleanBinary(BoundBinaryExpression* expres default: throw EvaluationException("Can't evaluate operation to boolean"); } +} + +StringEvalValue* Evaluator::EvaluateStringBinary(BoundBinaryExpression* expression){ + if (expression->GetOperation() != BoundBinaryOperation::Concatenation) + throw; + std::ostringstream strs; + auto left = this -> EvaluateStringExpression(expression->GetLeft()); + strs << left->EvaluateString(); + delete left; + auto right = this -> EvaluateExpression(expression->GetRight()); + strs << right->EvaluateString(); + delete right; + return new StringEvalValue(strs.str()); } \ No newline at end of file diff --git a/src/Evaluator/EvalValues/EvalValue.hpp b/src/Evaluator/EvalValues/EvalValue.hpp index e11f0ad..205d66a 100644 --- a/src/Evaluator/EvalValues/EvalValue.hpp +++ b/src/Evaluator/EvalValues/EvalValue.hpp @@ -5,6 +5,7 @@ #include "../../ScriptType.hpp" #include "../EvaluationException.hpp" #include +#include class EvalValue{ public: @@ -57,6 +58,12 @@ public: return false; return this->EvaluateBool() == b->EvaluateBool(); }; + + std::string EvaluateString() final{ + std::ostringstream strs; + strs << _value; + return strs.str(); + } }; #endif //PORYGONLANG_EVALVALUE_HPP diff --git a/src/Evaluator/EvalValues/NumericEvalValue.hpp b/src/Evaluator/EvalValues/NumericEvalValue.hpp index c6cc8d2..afd237c 100644 --- a/src/Evaluator/EvalValues/NumericEvalValue.hpp +++ b/src/Evaluator/EvalValues/NumericEvalValue.hpp @@ -2,6 +2,7 @@ #ifndef PORYGONLANG_NUMERICEVALVALUE_HPP #define PORYGONLANG_NUMERICEVALVALUE_HPP +#include #include "EvalValue.hpp" class NumericEvalValue : public EvalValue{ @@ -43,6 +44,12 @@ public: long EvaluateInteger() final{ return _value; } + + std::string EvaluateString() final{ + std::ostringstream strs; + strs << _value; + return strs.str(); + } }; class FloatEvalValue : public NumericEvalValue{ @@ -61,6 +68,12 @@ public: double EvaluateFloat() final{ return _value; } + + std::string EvaluateString() final{ + std::ostringstream strs; + strs << _value; + return strs.str(); + } }; #endif //PORYGONLANG_NUMERICEVALVALUE_HPP diff --git a/src/Evaluator/EvalValues/StringEvalValue.cpp b/src/Evaluator/EvalValues/StringEvalValue.cpp new file mode 100644 index 0000000..cde4137 --- /dev/null +++ b/src/Evaluator/EvalValues/StringEvalValue.cpp @@ -0,0 +1,2 @@ + +#include "StringEvalValue.hpp" diff --git a/src/Evaluator/EvalValues/StringEvalValue.hpp b/src/Evaluator/EvalValues/StringEvalValue.hpp new file mode 100644 index 0000000..66681da --- /dev/null +++ b/src/Evaluator/EvalValues/StringEvalValue.hpp @@ -0,0 +1,38 @@ + +#ifndef PORYGONLANG_STRINGEVALVALUE_HPP +#define PORYGONLANG_STRINGEVALVALUE_HPP + +#include +#include "EvalValue.hpp" + +using namespace std; + +class StringEvalValue : public EvalValue{ + string _value; + ScriptType* _type; +public: + explicit StringEvalValue(string s){ + _value = move(s); + _type = new ScriptType(TypeClass::String); + } + ~StringEvalValue() final{ + delete _type; + } + + ScriptType* GetType() final{ + return _type; + }; + bool operator ==(EvalValue* b) final{ + if (b->GetType()->GetClass() != TypeClass::String) + return false; + return this->_value == b->EvaluateString(); + }; + + string EvaluateString() final{ + return _value; + } + +}; + + +#endif //PORYGONLANG_STRINGEVALVALUE_HPP diff --git a/src/Evaluator/Evaluator.cpp b/src/Evaluator/Evaluator.cpp index 3b19f33..9d3a905 100644 --- a/src/Evaluator/Evaluator.cpp +++ b/src/Evaluator/Evaluator.cpp @@ -33,6 +33,7 @@ EvalValue *Evaluator::EvaluateExpression(BoundExpression *expression) { switch (type->GetClass()){ case TypeClass ::Number: return this -> EvaluateIntegerExpression(expression); case TypeClass ::Bool: return this -> EvaluateBoolExpression(expression); + case TypeClass ::String: return this -> EvaluateStringExpression(expression); default: throw; } } @@ -56,6 +57,7 @@ BooleanEvalValue* Evaluator::EvaluateBoolExpression(BoundExpression *expression) case BoundExpressionKind::LiteralBool: return new BooleanEvalValue(((BoundLiteralBoolExpression*)expression)->GetValue()); case BoundExpressionKind::Unary: return this -> EvaluateBooleanUnary((BoundUnaryExpression*)expression); case BoundExpressionKind::Binary: return this -> EvaluateBooleanBinary((BoundBinaryExpression*)expression); + case BoundExpressionKind::Bad: case BoundExpressionKind::LiteralInteger: case BoundExpressionKind::LiteralFloat: @@ -65,7 +67,19 @@ BooleanEvalValue* Evaluator::EvaluateBoolExpression(BoundExpression *expression) } } -EvalValue* Evaluator::EvaluateStringExpression(BoundExpression *expression) { - return nullptr; -} +StringEvalValue* Evaluator::EvaluateStringExpression(BoundExpression *expression) { + switch (expression->GetKind()) { + case BoundExpressionKind::LiteralString: + return new StringEvalValue(((BoundLiteralStringExpression*)expression)->GetValue()); + case BoundExpressionKind::Binary: + return this -> EvaluateStringBinary((BoundBinaryExpression*)expression); + + case BoundExpressionKind::Bad: + case BoundExpressionKind::LiteralInteger: + case BoundExpressionKind::LiteralFloat: + case BoundExpressionKind::LiteralBool: + case BoundExpressionKind::Unary: + throw; + + }} diff --git a/src/Evaluator/Evaluator.hpp b/src/Evaluator/Evaluator.hpp index 4b17db4..2df4e5e 100644 --- a/src/Evaluator/Evaluator.hpp +++ b/src/Evaluator/Evaluator.hpp @@ -8,6 +8,7 @@ #include "../Script.hpp" #include "EvalValues/EvalValue.hpp" #include "EvalValues/NumericEvalValue.hpp" +#include "EvalValues/StringEvalValue.hpp" using namespace boost; @@ -24,10 +25,11 @@ class Evaluator { EvalValue* EvaluateExpression(BoundExpression* expression); NumericEvalValue* EvaluateIntegerExpression(BoundExpression* expression); BooleanEvalValue* EvaluateBoolExpression(BoundExpression* expression); - EvalValue* EvaluateStringExpression(BoundExpression* expression); + StringEvalValue* EvaluateStringExpression(BoundExpression* expression); NumericEvalValue* EvaluateIntegerBinary(BoundBinaryExpression* expression); BooleanEvalValue *EvaluateBooleanBinary(BoundBinaryExpression *expression); + StringEvalValue *EvaluateStringBinary(BoundBinaryExpression *expression); NumericEvalValue* EvaluateIntegerUnary(BoundUnaryExpression* expression); BooleanEvalValue *EvaluateBooleanUnary(BoundUnaryExpression *expression); diff --git a/src/ScriptType.hpp b/src/ScriptType.hpp index 1262dd3..1275122 100644 --- a/src/ScriptType.hpp +++ b/src/ScriptType.hpp @@ -20,7 +20,7 @@ public: _class = c; } - TypeClass GetClass(){ + const TypeClass GetClass(){ return _class; } }; diff --git a/tests/integration/StringOperationsTests.cpp b/tests/integration/StringOperationsTests.cpp new file mode 100644 index 0000000..db7d695 --- /dev/null +++ b/tests/integration/StringOperationsTests.cpp @@ -0,0 +1,25 @@ + +#ifdef TESTS_BUILD +#include +#include "../src/Script.hpp" + + +TEST_CASE( "Simple String", "[integration]" ) { + Script script = Script::Create("\"foo bar\""); + REQUIRE(!script.Diagnostics -> HasErrors()); + script.Evaluate(); + auto lastValue = script.GetLastValue(); + REQUIRE(lastValue->EvaluateString() == "foo bar"); +} + +TEST_CASE( "String Concat", "[integration]" ) { + Script script = Script::Create("\"foo\" + \"bar\""); + REQUIRE(!script.Diagnostics -> HasErrors()); + script.Evaluate(); + auto lastValue = script.GetLastValue(); + REQUIRE(lastValue->EvaluateString() == "foobar"); +} + + +#endif +