From 7d75131822f38399b6ce9ad72a8b127187da32d4 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sat, 8 Jun 2019 15:38:08 +0200 Subject: [PATCH] Implemented comparison equality operators --- src/Binder/Binder.cpp | 20 ++++ src/Binder/BoundOperators.hpp | 5 + src/Evaluator/BinaryEvaluation.cpp | 29 +++++ src/Evaluator/EvalValues/NumericEvalValue.cpp | 64 +++++++++++ src/Evaluator/EvalValues/NumericEvalValue.hpp | 4 + src/Parser/BinaryOperatorKind.hpp | 9 ++ src/Parser/Lexer.cpp | 12 ++ src/Parser/Parser.cpp | 19 ++++ src/Parser/TokenKind.hpp | 5 + tests/integration/EqualityOperationsTests.cpp | 107 ++++++++++++++++++ 10 files changed, 274 insertions(+) diff --git a/src/Binder/Binder.cpp b/src/Binder/Binder.cpp index 5f09bf8..a0ef6b6 100644 --- a/src/Binder/Binder.cpp +++ b/src/Binder/Binder.cpp @@ -275,6 +275,26 @@ BoundExpression* Binder::BindBinaryOperator(BinaryExpression* expression){ case BinaryOperatorKind ::Inequality: return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Inequality, std::make_shared(TypeClass::Bool), expression->GetStartPosition(), expression->GetLength()); + case BinaryOperatorKind ::Less: + if (boundLeft->GetType()->GetClass() == TypeClass::Number && boundRight->GetType()->GetClass() == TypeClass::Number){ + return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::LessThan, std::make_shared(TypeClass::Bool), + expression->GetStartPosition(), expression->GetLength()); + } + case BinaryOperatorKind ::LessOrEquals: + if (boundLeft->GetType()->GetClass() == TypeClass::Number && boundRight->GetType()->GetClass() == TypeClass::Number){ + return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::LessThanEquals, std::make_shared(TypeClass::Bool), + expression->GetStartPosition(), expression->GetLength()); + } + case BinaryOperatorKind ::Greater: + if (boundLeft->GetType()->GetClass() == TypeClass::Number && boundRight->GetType()->GetClass() == TypeClass::Number){ + return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::GreaterThan, std::make_shared(TypeClass::Bool), + expression->GetStartPosition(), expression->GetLength()); + } + case BinaryOperatorKind ::GreaterOrEquals: + if (boundLeft->GetType()->GetClass() == TypeClass::Number && boundRight->GetType()->GetClass() == TypeClass::Number){ + return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::GreaterThanEquals, std::make_shared(TypeClass::Bool), + expression->GetStartPosition(), expression->GetLength()); + } case BinaryOperatorKind ::LogicalAnd: if (boundLeftType->GetClass() == TypeClass::Bool && boundRightType->GetClass() == TypeClass::Bool) return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::LogicalAnd, std::make_shared(TypeClass::Bool), diff --git a/src/Binder/BoundOperators.hpp b/src/Binder/BoundOperators.hpp index 2385eb2..b768872 100644 --- a/src/Binder/BoundOperators.hpp +++ b/src/Binder/BoundOperators.hpp @@ -9,6 +9,11 @@ enum class BoundBinaryOperation{ Division, Equality, Inequality, + LessThan, + LessThanEquals, + GreaterThan, + GreaterThanEquals, + LogicalAnd, LogicalOr, Concatenation diff --git a/src/Evaluator/BinaryEvaluation.cpp b/src/Evaluator/BinaryEvaluation.cpp index f374407..f880b69 100644 --- a/src/Evaluator/BinaryEvaluation.cpp +++ b/src/Evaluator/BinaryEvaluation.cpp @@ -45,6 +45,35 @@ shared_ptr Evaluator::EvaluateBooleanBinary(BoundBinaryExpress bool equals = leftValue.get()->operator!=(rightValue.get()); return make_shared(equals); } + case BoundBinaryOperation ::LessThan: + { + auto leftValue = this -> EvaluateIntegerExpression(expression->GetLeft()); + auto rightValue = this -> EvaluateIntegerExpression(expression->GetRight()); + BooleanEvalValue* b = leftValue->operator<(rightValue.get()); + return shared_ptr(b); + } + case BoundBinaryOperation ::LessThanEquals: + { + auto leftValue = this -> EvaluateIntegerExpression(expression->GetLeft()); + auto rightValue = this -> EvaluateIntegerExpression(expression->GetRight()); + BooleanEvalValue* b = leftValue->operator<=(rightValue.get()); + return shared_ptr(b); + } + case BoundBinaryOperation ::GreaterThan: + { + auto leftValue = this -> EvaluateIntegerExpression(expression->GetLeft()); + auto rightValue = this -> EvaluateIntegerExpression(expression->GetRight()); + BooleanEvalValue* b = leftValue->operator>(rightValue.get()); + return shared_ptr(b); + } + case BoundBinaryOperation ::GreaterThanEquals: + { + auto leftValue = this -> EvaluateIntegerExpression(expression->GetLeft()); + auto rightValue = this -> EvaluateIntegerExpression(expression->GetRight()); + BooleanEvalValue* b = leftValue->operator>=(rightValue.get()); + return shared_ptr(b); + } + case BoundBinaryOperation::LogicalAnd: { auto leftValue = this -> EvaluateBoolExpression(expression->GetLeft()); diff --git a/src/Evaluator/EvalValues/NumericEvalValue.cpp b/src/Evaluator/EvalValues/NumericEvalValue.cpp index 56e5e81..9b788da 100644 --- a/src/Evaluator/EvalValues/NumericEvalValue.cpp +++ b/src/Evaluator/EvalValues/NumericEvalValue.cpp @@ -78,3 +78,67 @@ bool NumericEvalValue::operator==(EvalValue *b) { return this->EvaluateInteger() == numVal->EvaluateInteger(); } } + +BooleanEvalValue *NumericEvalValue::operator<(NumericEvalValue *b) { + if (this->IsFloat()){ + if (b->IsFloat()){ + return new BooleanEvalValue(this->GetFloatValue() < b->GetFloatValue()); + } else{ + return new BooleanEvalValue(this->GetFloatValue() < b->GetIntegerValue()); + } + } else { + if (b->IsFloat()){ + return new BooleanEvalValue(this->GetIntegerValue() < b->GetFloatValue()); + } else{ + return new BooleanEvalValue(this->GetIntegerValue() < b->GetIntegerValue()); + } + } +} + +BooleanEvalValue *NumericEvalValue::operator<=(NumericEvalValue *b) { + if (this->IsFloat()){ + if (b->IsFloat()){ + return new BooleanEvalValue(this->GetFloatValue() <= b->GetFloatValue()); + } else{ + return new BooleanEvalValue(this->GetFloatValue() <= b->GetIntegerValue()); + } + } else { + if (b->IsFloat()){ + return new BooleanEvalValue(this->GetIntegerValue() <= b->GetFloatValue()); + } else{ + return new BooleanEvalValue(this->GetIntegerValue() <= b->GetIntegerValue()); + } + } +} + +BooleanEvalValue *NumericEvalValue::operator>(NumericEvalValue *b) { + if (this->IsFloat()){ + if (b->IsFloat()){ + return new BooleanEvalValue(this->GetFloatValue() > b->GetFloatValue()); + } else{ + return new BooleanEvalValue(this->GetFloatValue() > b->GetIntegerValue()); + } + } else { + if (b->IsFloat()){ + return new BooleanEvalValue(this->GetIntegerValue() > b->GetFloatValue()); + } else{ + return new BooleanEvalValue(this->GetIntegerValue() > b->GetIntegerValue()); + } + } +} + +BooleanEvalValue *NumericEvalValue::operator>=(NumericEvalValue *b) { + if (this->IsFloat()){ + if (b->IsFloat()){ + return new BooleanEvalValue(this->GetFloatValue() >= b->GetFloatValue()); + } else{ + return new BooleanEvalValue(this->GetFloatValue() >= b->GetIntegerValue()); + } + } else { + if (b->IsFloat()){ + return new BooleanEvalValue(this->GetIntegerValue() >= b->GetFloatValue()); + } else{ + return new BooleanEvalValue(this->GetIntegerValue() >= b->GetIntegerValue()); + } + } +} diff --git a/src/Evaluator/EvalValues/NumericEvalValue.hpp b/src/Evaluator/EvalValues/NumericEvalValue.hpp index fcafa63..602a87b 100644 --- a/src/Evaluator/EvalValues/NumericEvalValue.hpp +++ b/src/Evaluator/EvalValues/NumericEvalValue.hpp @@ -22,6 +22,10 @@ public: NumericEvalValue* operator -(NumericEvalValue* b); NumericEvalValue* operator *(NumericEvalValue* b); NumericEvalValue* operator /(NumericEvalValue* b); + BooleanEvalValue* operator <(NumericEvalValue* b); + BooleanEvalValue* operator <=(NumericEvalValue* b); + BooleanEvalValue* operator >(NumericEvalValue* b); + BooleanEvalValue* operator >=(NumericEvalValue* b); bool operator ==(EvalValue* b) final; }; diff --git a/src/Parser/BinaryOperatorKind.hpp b/src/Parser/BinaryOperatorKind.hpp index 352e8b2..5de5087 100644 --- a/src/Parser/BinaryOperatorKind.hpp +++ b/src/Parser/BinaryOperatorKind.hpp @@ -2,12 +2,21 @@ #ifndef PORYGONLANG_BINARYOPERATORKIND_HPP #define PORYGONLANG_BINARYOPERATORKIND_HPP enum class BinaryOperatorKind{ + // Math Addition, Subtraction, Multiplication, Division, + + // Equality Equality, Inequality, + Less, + LessOrEquals, + Greater, + GreaterOrEquals, + + // Logical LogicalAnd, LogicalOr, }; diff --git a/src/Parser/Lexer.cpp b/src/Parser/Lexer.cpp index 9753034..2f3999c 100644 --- a/src/Parser/Lexer.cpp +++ b/src/Parser/Lexer.cpp @@ -79,6 +79,18 @@ IToken* Lexer::LexNext(char c){ return new SimpleToken(TokenKind::EqualityToken, this -> _position - 2, 2); } return new SimpleToken(TokenKind::AssignmentToken, this -> _position - 1, 1); + case '<': + if (Lexer::Peek() == '='){ + Lexer::Next(); + return new SimpleToken(TokenKind::LessEquals, this -> _position - 2, 2); + } + return new SimpleToken(TokenKind::Less, this -> _position - 1, 1); + case '>': + if (Lexer::Peek() == '='){ + Lexer::Next(); + return new SimpleToken(TokenKind::GreaterEquals, this -> _position - 2, 2); + } + return new SimpleToken(TokenKind::Greater, this -> _position - 1, 1); case '~': if (Lexer::Peek() == '='){ Lexer::Next(); diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index 31a77a2..a77ed1c 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -223,12 +223,21 @@ UnaryOperatorKind GetUnaryOperatorKind(TokenKind kind){ BinaryOperatorKind GetBinaryOperatorKind(TokenKind kind){ switch (kind){ + // Math operators case TokenKind::PlusToken: return BinaryOperatorKind ::Addition; case TokenKind::MinusToken: return BinaryOperatorKind ::Subtraction; case TokenKind::StarToken: return BinaryOperatorKind ::Multiplication; case TokenKind::SlashToken: return BinaryOperatorKind ::Division; + + // Equality operators case TokenKind::EqualityToken: return BinaryOperatorKind ::Equality; case TokenKind::InequalityToken: return BinaryOperatorKind ::Inequality; + case TokenKind ::Less: return BinaryOperatorKind ::Less; + case TokenKind ::LessEquals: return BinaryOperatorKind ::LessOrEquals; + case TokenKind ::Greater: return BinaryOperatorKind ::Greater; + case TokenKind ::GreaterEquals: return BinaryOperatorKind ::GreaterOrEquals; + + // logical operators case TokenKind::AndKeyword: return BinaryOperatorKind ::LogicalAnd; case TokenKind::OrKeyword: return BinaryOperatorKind ::LogicalOr; default: // This should never trigger, so throw. @@ -238,12 +247,22 @@ BinaryOperatorKind GetBinaryOperatorKind(TokenKind kind){ OperatorPrecedence GetBinaryPrecedence(TokenKind kind){ switch (kind){ + // Math case TokenKind::PlusToken: return OperatorPrecedence ::Additive; case TokenKind::MinusToken: return OperatorPrecedence ::Additive; case TokenKind::StarToken: return OperatorPrecedence ::Multiplication; case TokenKind::SlashToken: return OperatorPrecedence ::Multiplication; + + // Equality case TokenKind::EqualityToken: return OperatorPrecedence ::Equality; case TokenKind::InequalityToken: return OperatorPrecedence ::Equality; + case TokenKind ::Less: return OperatorPrecedence ::Equality; + case TokenKind ::LessEquals: return OperatorPrecedence ::Equality; + case TokenKind ::Greater: return OperatorPrecedence ::Equality; + case TokenKind ::GreaterEquals: return OperatorPrecedence ::Equality; + + + // Logical case TokenKind::AndKeyword: return OperatorPrecedence ::LogicalAnd; case TokenKind::OrKeyword: return OperatorPrecedence ::LogicalOr; default: diff --git a/src/Parser/TokenKind.hpp b/src/Parser/TokenKind.hpp index cedb6de..a98a4a6 100644 --- a/src/Parser/TokenKind.hpp +++ b/src/Parser/TokenKind.hpp @@ -13,6 +13,11 @@ enum class TokenKind{ AssignmentToken, EqualityToken, InequalityToken, + Less, + LessEquals, + Greater, + GreaterEquals, + OpenParenthesis, CloseParenthesis, OpenSquareBracket, diff --git a/tests/integration/EqualityOperationsTests.cpp b/tests/integration/EqualityOperationsTests.cpp index 94eae7b..7edf93f 100644 --- a/tests/integration/EqualityOperationsTests.cpp +++ b/tests/integration/EqualityOperationsTests.cpp @@ -63,6 +63,113 @@ TEST_CASE( "10 Not Equals 5", "[integration]" ) { delete script; } +TEST_CASE( "10 < 5 == false", "[integration]" ) { + auto script = Script::Create("10 < 5"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); + REQUIRE_FALSE(lastValue->EvaluateBool()); + delete script; +} + +TEST_CASE( "2 < 60 == true", "[integration]" ) { + auto script = Script::Create("2 < 60"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); + REQUIRE(lastValue->EvaluateBool()); + delete script; +} + +TEST_CASE( "5 < 5 == false", "[integration]" ) { + auto script = Script::Create("5 < 5"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); + REQUIRE_FALSE(lastValue->EvaluateBool()); + delete script; +} + +TEST_CASE( "10 <= 5 == false", "[integration]" ) { + auto script = Script::Create("10 <= 5"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); + REQUIRE_FALSE(lastValue->EvaluateBool()); + delete script; +} + +TEST_CASE( "2 <= 60 == true", "[integration]" ) { + auto script = Script::Create("2 <= 60"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); + REQUIRE(lastValue->EvaluateBool()); + delete script; +} + +TEST_CASE( "5 <= 5 == true", "[integration]" ) { + auto script = Script::Create("5 <= 5"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); + REQUIRE(lastValue->EvaluateBool()); + delete script; +} + +TEST_CASE( "10 > 5 == true", "[integration]" ) { + auto script = Script::Create("10 > 5"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); + REQUIRE(lastValue->EvaluateBool()); + delete script; +} + +TEST_CASE( "2 > 60 == false", "[integration]" ) { + auto script = Script::Create("2 > 60"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); + REQUIRE_FALSE(lastValue->EvaluateBool()); + delete script; +} + +TEST_CASE( "5 > 5 == false", "[integration]" ) { + auto script = Script::Create("5 > 5"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); + REQUIRE_FALSE(lastValue->EvaluateBool()); + delete script; +} + +TEST_CASE( "10 >= 5 == true", "[integration]" ) { + auto script = Script::Create("10 >= 5"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); + REQUIRE(lastValue->EvaluateBool()); + delete script; +} + +TEST_CASE( "2 >= 60 == false", "[integration]" ) { + auto script = Script::Create("2 >= 60"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); + REQUIRE_FALSE(lastValue->EvaluateBool()); + delete script; +} + +TEST_CASE( "5 >= 5 == true", "[integration]" ) { + auto script = Script::Create("5 >= 5"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); + REQUIRE(lastValue->EvaluateBool()); + delete script; +} #endif