diff --git a/src/Binder/Binder.cpp b/src/Binder/Binder.cpp index 72f6f68..281abc6 100644 --- a/src/Binder/Binder.cpp +++ b/src/Binder/Binder.cpp @@ -540,6 +540,31 @@ namespace Porygon::Binder { } } break; + case BinaryOperatorKind::Exponent: + if (boundLeftType->GetClass() == TypeClass::Number && boundRightType->GetClass() == TypeClass::Number) { + return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Exponent, + NumericScriptType::AwareFloat, + expression->GetStartPosition(), expression->GetLength()); + } + break; + case BinaryOperatorKind::Modulus: + if (boundLeftType->GetClass() == TypeClass::Number && boundRightType->GetClass() == TypeClass::Number) { + auto leftNumeric = std::dynamic_pointer_cast(boundLeftType); + auto rightNumeric = std::dynamic_pointer_cast(boundRightType); + if (leftNumeric->IsAwareOfFloat() && rightNumeric->IsAwareOfFloat()) { + return new BoundBinaryExpression(boundLeft, boundRight, + BoundBinaryOperation::Modulus, + NumericScriptType::ResolveType(true, + leftNumeric->IsFloat() || + rightNumeric->IsFloat()), + expression->GetStartPosition(), expression->GetLength()); + } else { + return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Modulus, + NumericScriptType::Unaware, + expression->GetStartPosition(), expression->GetLength()); + } + } + break; case BinaryOperatorKind::Equality: return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Equality, ScriptType::BoolType, diff --git a/src/Binder/BoundExpressions/BoundExpression.hpp b/src/Binder/BoundExpressions/BoundExpression.hpp index ce9a216..6ec1eb9 100644 --- a/src/Binder/BoundExpressions/BoundExpression.hpp +++ b/src/Binder/BoundExpressions/BoundExpression.hpp @@ -279,11 +279,13 @@ namespace Porygon::Binder { static std::string GetOperationString(BoundBinaryOperation op){ switch (op){ - case BoundBinaryOperation::Addition: return "addition"; case BoundBinaryOperation::Subtraction: return "subtraction"; case BoundBinaryOperation::Multiplication: return "multiplication"; case BoundBinaryOperation::Division: return "division"; + case BoundBinaryOperation::Modulus: return "modulus"; + case BoundBinaryOperation::Exponent: return "exponent"; + case BoundBinaryOperation::Equality: return "equality"; case BoundBinaryOperation::Inequality: return "inequality"; case BoundBinaryOperation::LessThan: return "lessThan"; diff --git a/src/Binder/BoundOperators.hpp b/src/Binder/BoundOperators.hpp index ffb1d27..290beee 100644 --- a/src/Binder/BoundOperators.hpp +++ b/src/Binder/BoundOperators.hpp @@ -9,6 +9,8 @@ namespace Porygon::Binder { Subtraction = 1, Multiplication = 2, Division = 3, + Modulus = 13, + Exponent = 14, Equality = 4, Inequality = 5, LessThan = 6, diff --git a/src/Evaluator/EvalValues/NumericEvalValue.cpp b/src/Evaluator/EvalValues/NumericEvalValue.cpp index d7457ac..f5e59aa 100644 --- a/src/Evaluator/EvalValues/NumericEvalValue.cpp +++ b/src/Evaluator/EvalValues/NumericEvalValue.cpp @@ -1,5 +1,6 @@ #include "NumericEvalValue.hpp" +#include namespace Porygon::Evaluation { EvalValue *NumericEvalValue::BinaryOperation(Binder::BoundBinaryOperation operation, const EvalValue *b) const { @@ -14,6 +15,8 @@ namespace Porygon::Evaluation { case Binder::BoundBinaryOperation::Subtraction: return new NumericEvalValue(v1 - v2); case Binder::BoundBinaryOperation::Multiplication: return new NumericEvalValue(v1 * v2); case Binder::BoundBinaryOperation::Division: return new NumericEvalValue(v1 / v2); + case Binder::BoundBinaryOperation::Exponent: return new NumericEvalValue(std::pow(v1, v2)); + case Binder::BoundBinaryOperation::Modulus: return new NumericEvalValue(std::fmod(v1, v2)); case Binder::BoundBinaryOperation::Equality: return new BooleanEvalValue(v1 == v2); case Binder::BoundBinaryOperation::Inequality: return new BooleanEvalValue(v1 != v2); case Binder::BoundBinaryOperation::LessThan: return new BooleanEvalValue(v1 < v2); @@ -31,6 +34,8 @@ namespace Porygon::Evaluation { case Binder::BoundBinaryOperation::Subtraction: return new NumericEvalValue(v1 - v2); case Binder::BoundBinaryOperation::Multiplication: return new NumericEvalValue(v1 * v2); case Binder::BoundBinaryOperation::Division: return new NumericEvalValue(v1 / v2); + case Binder::BoundBinaryOperation::Exponent: return new NumericEvalValue(std::pow(v1, v2)); + case Binder::BoundBinaryOperation::Modulus: return new NumericEvalValue(std::fmod(v1, v2)); case Binder::BoundBinaryOperation::Equality: return new BooleanEvalValue(v1 == v2); case Binder::BoundBinaryOperation::Inequality: return new BooleanEvalValue(v1 != v2); case Binder::BoundBinaryOperation::LessThan: return new BooleanEvalValue(v1 < v2); @@ -44,13 +49,15 @@ namespace Porygon::Evaluation { else{ int64_t v1 = std::get(_intValue); if (right->_isFloat){ - double v2 =std::get(right->_floatValue);; + double v2 =std::get(right->_floatValue); switch (operation){ case Binder::BoundBinaryOperation::Addition: return new NumericEvalValue(v1 + v2); case Binder::BoundBinaryOperation::Subtraction: return new NumericEvalValue(v1 - v2); case Binder::BoundBinaryOperation::Multiplication: return new NumericEvalValue(v1 * v2); case Binder::BoundBinaryOperation::Division: return new NumericEvalValue(v1 / v2); + case Binder::BoundBinaryOperation::Exponent: return new NumericEvalValue(std::pow(v1, v2)); + case Binder::BoundBinaryOperation::Modulus: return new NumericEvalValue(std::fmod(v1, v2)); case Binder::BoundBinaryOperation::Equality: return new BooleanEvalValue(v1 == v2); case Binder::BoundBinaryOperation::Inequality: return new BooleanEvalValue(v1 != v2); case Binder::BoundBinaryOperation::LessThan: return new BooleanEvalValue(v1 < v2); @@ -67,6 +74,8 @@ namespace Porygon::Evaluation { case Binder::BoundBinaryOperation::Subtraction: return new NumericEvalValue(v1 - v2); case Binder::BoundBinaryOperation::Multiplication: return new NumericEvalValue(v1 * v2); case Binder::BoundBinaryOperation::Division: return new NumericEvalValue(v1 / v2); + case Binder::BoundBinaryOperation::Exponent: return new NumericEvalValue(std::pow(v1, v2)); + case Binder::BoundBinaryOperation::Modulus: return new NumericEvalValue(v1 % v2); case Binder::BoundBinaryOperation::Equality: return new BooleanEvalValue(v1 == v2); case Binder::BoundBinaryOperation::Inequality: return new BooleanEvalValue(v1 != v2); case Binder::BoundBinaryOperation::LessThan: return new BooleanEvalValue(v1 < v2); @@ -101,7 +110,7 @@ namespace Porygon::Evaluation { size_t NumericEvalValue::GetHashCode() const { if (_isFloat) return std::get(_floatValue); - return std::get(_intValue);; + return std::get(_intValue); } bool NumericEvalValue::operator==(const EvalValue *b) const { @@ -117,7 +126,7 @@ namespace Porygon::Evaluation { } int64_t NumericEvalValue::EvaluateInteger() const { - return std::get(_intValue);; + return std::get(_intValue); } double NumericEvalValue::EvaluateFloat() const { diff --git a/src/Parser/BinaryOperatorKind.hpp b/src/Parser/BinaryOperatorKind.hpp index 82469e6..38711ef 100644 --- a/src/Parser/BinaryOperatorKind.hpp +++ b/src/Parser/BinaryOperatorKind.hpp @@ -9,6 +9,8 @@ namespace Porygon::Parser { Subtraction, Multiplication, Division, + Exponent, + Modulus, // Equality Equality, diff --git a/src/Parser/Lexer.cpp b/src/Parser/Lexer.cpp index 9a5e881..85c76a8 100644 --- a/src/Parser/Lexer.cpp +++ b/src/Parser/Lexer.cpp @@ -111,6 +111,10 @@ namespace Porygon::Parser { return new SimpleToken(TokenKind::BadToken, this->_position - 1, 1); case '#': return new SimpleToken(TokenKind::HashToken, this->_position - 1, 1); + case '^': + return new SimpleToken(TokenKind::RoofToken, this->_position - 1, 1); + case '%': + return new SimpleToken(TokenKind::PercentToken, this->_position - 1, 1); case '0': case '1': case '2': diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index 4438e1c..a979640 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -414,6 +414,10 @@ namespace Porygon::Parser { return BinaryOperatorKind::Multiplication; case TokenKind::SlashToken: return BinaryOperatorKind::Division; + case TokenKind::RoofToken: + return BinaryOperatorKind ::Exponent; + case TokenKind::PercentToken: + return BinaryOperatorKind ::Modulus; // Equality operators case TokenKind::EqualityToken: @@ -450,6 +454,11 @@ namespace Porygon::Parser { return OperatorPrecedence::Multiplication; case TokenKind::SlashToken: return OperatorPrecedence::Multiplication; + case TokenKind::RoofToken: + return OperatorPrecedence ::Multiplication; + case TokenKind::PercentToken: + return OperatorPrecedence ::Multiplication; + // Equality case TokenKind::EqualityToken: diff --git a/src/Parser/TokenKind.hpp b/src/Parser/TokenKind.hpp index ec0785e..41a7884 100644 --- a/src/Parser/TokenKind.hpp +++ b/src/Parser/TokenKind.hpp @@ -20,6 +20,8 @@ namespace Porygon::Parser { Greater, GreaterEquals, HashToken, + RoofToken, + PercentToken, OpenParenthesis, CloseParenthesis, diff --git a/tests/integration/NumericalOperationsTests.cpp b/tests/integration/NumericalOperationsTests.cpp index b91613c..ea70d46 100644 --- a/tests/integration/NumericalOperationsTests.cpp +++ b/tests/integration/NumericalOperationsTests.cpp @@ -47,6 +47,22 @@ TEST_CASE( "Integer Division", "[integration]" ) { delete script; } +TEST_CASE( "Integer Exponent", "[integration]" ) { + auto script = Script::Create("return 9 ^ 3"); + REQUIRE(!script->Diagnostics -> HasErrors()); + auto result = script->Evaluate(); + REQUIRE(result->EvaluateFloat() == 729); + delete script; +} + +TEST_CASE( "Integer Modulus", "[integration]" ) { + auto script = Script::Create("return 9 % 2"); + REQUIRE(!script->Diagnostics -> HasErrors()); + auto result = script->Evaluate(); + REQUIRE(result->EvaluateInteger() == 1); + delete script; +} + TEST_CASE( "Float Addition", "[integration]" ) { auto script = Script::Create("1.2 + 5.34"); REQUIRE(!script->Diagnostics -> HasErrors()); @@ -75,4 +91,21 @@ TEST_CASE( "Float Division", "[integration]" ) { REQUIRE(result->EvaluateFloat() == Approx(10.7305524239)); delete script; } + +TEST_CASE( "Float Exponent", "[integration]" ) { + auto script = Script::Create("95.18 ^ 2.0"); + REQUIRE(!script->Diagnostics -> HasErrors()); + auto result = script->Evaluate(); + REQUIRE(result->EvaluateFloat() == Approx(9059.2324)); + delete script; +} + +TEST_CASE( "Float Modulus", "[integration]" ) { + auto script = Script::Create("return 9.2 % 2.0"); + REQUIRE(!script->Diagnostics -> HasErrors()); + auto result = script->Evaluate(); + REQUIRE(result->EvaluateFloat() == Approx(1.2)); + delete script; +} + #endif