diff --git a/src/ObjLoading/Parsing/Menu/Domain/Expression/CommonExpressionBinaryOperation.cpp b/src/ObjLoading/Parsing/Menu/Domain/Expression/CommonExpressionBinaryOperation.cpp new file mode 100644 index 00000000..390abe40 --- /dev/null +++ b/src/ObjLoading/Parsing/Menu/Domain/Expression/CommonExpressionBinaryOperation.cpp @@ -0,0 +1,418 @@ +#include "CommonExpressionBinaryOperation.h" + +#include +#include + +using namespace menu; + +CommonExpressionBinaryOperationType::CommonExpressionBinaryOperationType(std::string syntax, const OperationPrecedence precedence, evaluation_function_t evaluationFunction) + : m_syntax(std::move(syntax)), + m_precedence(precedence), + m_evaluation_function(std::move(evaluationFunction)) +{ +} + +const CommonExpressionBinaryOperationType CommonExpressionBinaryOperationType::OPERATION_ADD( + "+", + OperationPrecedence::ADDITION_SUBTRACTION, + [](const CommonExpressionValue& operand1, const CommonExpressionValue& operand2) -> CommonExpressionValue + { + if (operand1.m_type == CommonExpressionValue::Type::DOUBLE) + { + if (operand2.m_type == CommonExpressionValue::Type::DOUBLE) + return CommonExpressionValue(operand1.m_double_value + operand2.m_double_value); + if (operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(operand1.m_double_value + static_cast(operand2.m_int_value)); + if (operand2.m_type == CommonExpressionValue::Type::STRING) + return CommonExpressionValue(std::to_string(operand1.m_double_value) + *operand2.m_string_value); + } + else if (operand1.m_type == CommonExpressionValue::Type::INT) + { + if (operand2.m_type == CommonExpressionValue::Type::DOUBLE) + return CommonExpressionValue(static_cast(operand1.m_int_value) + operand2.m_double_value); + if (operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(operand1.m_int_value + operand2.m_int_value); + if (operand2.m_type == CommonExpressionValue::Type::STRING) + return CommonExpressionValue(std::to_string(operand1.m_int_value) + *operand2.m_string_value); + } + else if (operand1.m_type == CommonExpressionValue::Type::STRING) + { + if (operand2.m_type == CommonExpressionValue::Type::DOUBLE) + return CommonExpressionValue(*operand1.m_string_value + std::to_string(operand2.m_double_value)); + if (operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(*operand1.m_string_value + std::to_string(operand2.m_int_value)); + if (operand2.m_type == CommonExpressionValue::Type::STRING) + return CommonExpressionValue(*operand1.m_string_value + *operand2.m_string_value); + } + + return CommonExpressionValue(0); + } +); + +const CommonExpressionBinaryOperationType CommonExpressionBinaryOperationType::OPERATION_SUBTRACT( + "-", + OperationPrecedence::ADDITION_SUBTRACTION, + [](const CommonExpressionValue& operand1, const CommonExpressionValue& operand2) -> CommonExpressionValue + { + if (operand1.m_type == CommonExpressionValue::Type::DOUBLE) + { + if (operand2.m_type == CommonExpressionValue::Type::DOUBLE) + return CommonExpressionValue(operand1.m_double_value - operand2.m_double_value); + if (operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(operand1.m_double_value - static_cast(operand2.m_int_value)); + } + else if (operand1.m_type == CommonExpressionValue::Type::INT) + { + if (operand2.m_type == CommonExpressionValue::Type::DOUBLE) + return CommonExpressionValue(static_cast(operand1.m_int_value) - operand2.m_double_value); + if (operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(operand1.m_int_value - operand2.m_int_value); + } + + return CommonExpressionValue(0); + } +); + +const CommonExpressionBinaryOperationType CommonExpressionBinaryOperationType::OPERATION_MULTIPLY( + "*", + OperationPrecedence::MULTIPLICATION_DIVISION_REMAINDER, + [](const CommonExpressionValue& operand1, const CommonExpressionValue& operand2) -> CommonExpressionValue + { + if (operand1.m_type == CommonExpressionValue::Type::DOUBLE) + { + if (operand2.m_type == CommonExpressionValue::Type::DOUBLE) + return CommonExpressionValue(operand1.m_double_value * operand2.m_double_value); + if (operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(operand1.m_double_value * static_cast(operand2.m_int_value)); + } + else if (operand1.m_type == CommonExpressionValue::Type::INT) + { + if (operand2.m_type == CommonExpressionValue::Type::DOUBLE) + return CommonExpressionValue(static_cast(operand1.m_int_value) * operand2.m_double_value); + if (operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(operand1.m_int_value * operand2.m_int_value); + } + + return CommonExpressionValue(0); + } +); + +const CommonExpressionBinaryOperationType CommonExpressionBinaryOperationType::OPERATION_DIVIDE( + "/", + OperationPrecedence::MULTIPLICATION_DIVISION_REMAINDER, + [](const CommonExpressionValue& operand1, const CommonExpressionValue& operand2) -> CommonExpressionValue + { + if (operand1.m_type == CommonExpressionValue::Type::DOUBLE) + { + if (operand2.m_type == CommonExpressionValue::Type::DOUBLE) + return CommonExpressionValue(operand1.m_double_value / operand2.m_double_value); + if (operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(operand1.m_double_value / static_cast(operand2.m_int_value)); + } + else if (operand1.m_type == CommonExpressionValue::Type::INT) + { + if (operand2.m_type == CommonExpressionValue::Type::DOUBLE) + return CommonExpressionValue(static_cast(operand1.m_int_value) / operand2.m_double_value); + if (operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(operand1.m_int_value / operand2.m_int_value); + } + + return CommonExpressionValue(0); + } +); + +const CommonExpressionBinaryOperationType CommonExpressionBinaryOperationType::OPERATION_REMAINDER( + "%", + OperationPrecedence::MULTIPLICATION_DIVISION_REMAINDER, + [](const CommonExpressionValue& operand1, const CommonExpressionValue& operand2) -> CommonExpressionValue + { + if (operand1.m_type == CommonExpressionValue::Type::INT && operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(operand1.m_int_value % operand2.m_int_value); + + return CommonExpressionValue(0); + } +); + +const CommonExpressionBinaryOperationType CommonExpressionBinaryOperationType::OPERATION_BITWISE_AND( + "&", + OperationPrecedence::BITWISE_AND, + [](const CommonExpressionValue& operand1, const CommonExpressionValue& operand2) -> CommonExpressionValue + { + if (operand1.m_type == CommonExpressionValue::Type::INT && operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(operand1.m_int_value & operand2.m_int_value); + + return CommonExpressionValue(0); + } +); + +const CommonExpressionBinaryOperationType CommonExpressionBinaryOperationType::OPERATION_BITWISE_OR( + "|", + OperationPrecedence::BITWISE_OR, + [](const CommonExpressionValue& operand1, const CommonExpressionValue& operand2) -> CommonExpressionValue + { + if (operand1.m_type == CommonExpressionValue::Type::INT && operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(operand1.m_int_value | operand2.m_int_value); + + return CommonExpressionValue(0); + } +); + +const CommonExpressionBinaryOperationType CommonExpressionBinaryOperationType::OPERATION_SHIFT_LEFT( + "<<", + OperationPrecedence::BITWISE_SHIFT, + [](const CommonExpressionValue& operand1, const CommonExpressionValue& operand2) -> CommonExpressionValue + { + if (operand1.m_type == CommonExpressionValue::Type::INT && operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(operand1.m_int_value << operand2.m_int_value); + + return CommonExpressionValue(0); + } +); + +const CommonExpressionBinaryOperationType CommonExpressionBinaryOperationType::OPERATION_SHIFT_RIGHT( + ">>", + OperationPrecedence::BITWISE_SHIFT, + [](const CommonExpressionValue& operand1, const CommonExpressionValue& operand2) -> CommonExpressionValue + { + if (operand1.m_type == CommonExpressionValue::Type::INT && operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(operand1.m_int_value >> operand2.m_int_value); + + return CommonExpressionValue(0); + } +); + +const CommonExpressionBinaryOperationType CommonExpressionBinaryOperationType::OPERATION_GREATER_THAN( + ">", + OperationPrecedence::RELATIONAL_GREATER_LESS_THAN, + [](const CommonExpressionValue& operand1, const CommonExpressionValue& operand2) -> CommonExpressionValue + { + if (operand1.m_type == CommonExpressionValue::Type::STRING || operand2.m_type == CommonExpressionValue::Type::STRING) + return CommonExpressionValue(operand1.IsTruthy() > operand2.IsTruthy()); + + if (operand1.m_type == CommonExpressionValue::Type::DOUBLE) + { + if (operand2.m_type == CommonExpressionValue::Type::DOUBLE) + return CommonExpressionValue(operand1.m_double_value > operand2.m_double_value); + if (operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(operand1.m_double_value > operand2.m_int_value); + } + else if (operand1.m_type == CommonExpressionValue::Type::INT) + { + if (operand2.m_type == CommonExpressionValue::Type::DOUBLE) + return CommonExpressionValue(operand1.m_int_value > operand2.m_double_value); + if (operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(operand1.m_int_value > operand2.m_int_value); + } + + return CommonExpressionValue(0); + } +); + +const CommonExpressionBinaryOperationType CommonExpressionBinaryOperationType::OPERATION_GREATER_EQUAL_THAN( + ">=", + OperationPrecedence::RELATIONAL_GREATER_LESS_THAN, + [](const CommonExpressionValue& operand1, const CommonExpressionValue& operand2) -> CommonExpressionValue + { + if (operand1.m_type == CommonExpressionValue::Type::STRING || operand2.m_type == CommonExpressionValue::Type::STRING) + return CommonExpressionValue(operand1.IsTruthy() >= operand2.IsTruthy()); + + if (operand1.m_type == CommonExpressionValue::Type::DOUBLE) + { + if (operand2.m_type == CommonExpressionValue::Type::DOUBLE) + return CommonExpressionValue(operand1.m_double_value >= operand2.m_double_value); + if (operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(operand1.m_double_value >= operand2.m_int_value); + } + else if (operand1.m_type == CommonExpressionValue::Type::INT) + { + if (operand2.m_type == CommonExpressionValue::Type::DOUBLE) + return CommonExpressionValue(operand1.m_int_value >= operand2.m_double_value); + if (operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(operand1.m_int_value >= operand2.m_int_value); + } + + return CommonExpressionValue(0); + } +); + +const CommonExpressionBinaryOperationType CommonExpressionBinaryOperationType::OPERATION_LESS_THAN( + "<", + OperationPrecedence::RELATIONAL_GREATER_LESS_THAN, + [](const CommonExpressionValue& operand1, const CommonExpressionValue& operand2) -> CommonExpressionValue + { + if (operand1.m_type == CommonExpressionValue::Type::STRING || operand2.m_type == CommonExpressionValue::Type::STRING) + return CommonExpressionValue(operand1.IsTruthy() < operand2.IsTruthy()); + + if (operand1.m_type == CommonExpressionValue::Type::DOUBLE) + { + if (operand2.m_type == CommonExpressionValue::Type::DOUBLE) + return CommonExpressionValue(operand1.m_double_value < operand2.m_double_value); + if (operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(operand1.m_double_value < operand2.m_int_value); + } + else if (operand1.m_type == CommonExpressionValue::Type::INT) + { + if (operand2.m_type == CommonExpressionValue::Type::DOUBLE) + return CommonExpressionValue(operand1.m_int_value < operand2.m_double_value); + if (operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(operand1.m_int_value < operand2.m_int_value); + } + + return CommonExpressionValue(0); + } +); + +const CommonExpressionBinaryOperationType CommonExpressionBinaryOperationType::OPERATION_LESS_EQUAL_THAN( + "<=", + OperationPrecedence::RELATIONAL_GREATER_LESS_THAN, + [](const CommonExpressionValue& operand1, const CommonExpressionValue& operand2) -> CommonExpressionValue + { + if (operand1.m_type == CommonExpressionValue::Type::STRING || operand2.m_type == CommonExpressionValue::Type::STRING) + return CommonExpressionValue(operand1.IsTruthy() <= operand2.IsTruthy()); + + if (operand1.m_type == CommonExpressionValue::Type::DOUBLE) + { + if (operand2.m_type == CommonExpressionValue::Type::DOUBLE) + return CommonExpressionValue(operand1.m_double_value <= operand2.m_double_value); + if (operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(operand1.m_double_value <= operand2.m_int_value); + } + else if (operand1.m_type == CommonExpressionValue::Type::INT) + { + if (operand2.m_type == CommonExpressionValue::Type::DOUBLE) + return CommonExpressionValue(operand1.m_int_value <= operand2.m_double_value); + if (operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(operand1.m_int_value <= operand2.m_int_value); + } + + return CommonExpressionValue(0); + } +); + +const CommonExpressionBinaryOperationType CommonExpressionBinaryOperationType::OPERATION_EQUALS( + "==", + OperationPrecedence::RELATIONAL_EQUALS, + [](const CommonExpressionValue& operand1, const CommonExpressionValue& operand2) -> CommonExpressionValue + { + if (operand1.m_type == CommonExpressionValue::Type::DOUBLE) + { + if (operand2.m_type == CommonExpressionValue::Type::DOUBLE) + return CommonExpressionValue(std::fpclassify(operand1.m_double_value - operand2.m_double_value) == FP_ZERO); + if (operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(std::fpclassify(operand1.m_double_value - static_cast(operand2.m_int_value)) == FP_ZERO); + + return CommonExpressionValue(0); + } + + if (operand1.m_type == CommonExpressionValue::Type::INT) + { + if (operand2.m_type == CommonExpressionValue::Type::DOUBLE) + return CommonExpressionValue(std::fpclassify(operand1.m_double_value - operand2.m_double_value) == FP_ZERO); + if (operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(operand1.m_int_value == operand2.m_int_value); + + return CommonExpressionValue(0); + } + + if (operand1.m_type == CommonExpressionValue::Type::STRING) + { + if (operand2.m_type == CommonExpressionValue::Type::STRING) + return CommonExpressionValue(*operand1.m_string_value == *operand2.m_string_value); + + return CommonExpressionValue(0); + } + + return CommonExpressionValue(0); + } +); + +const CommonExpressionBinaryOperationType CommonExpressionBinaryOperationType::OPERATION_NOT_EQUAL( + "!=", + OperationPrecedence::RELATIONAL_EQUALS, + [](const CommonExpressionValue& operand1, const CommonExpressionValue& operand2) -> CommonExpressionValue + { + if (operand1.m_type == CommonExpressionValue::Type::DOUBLE) + { + if (operand2.m_type == CommonExpressionValue::Type::DOUBLE) + return CommonExpressionValue(std::fpclassify(operand1.m_double_value - operand2.m_double_value) != FP_ZERO); + if (operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(std::fpclassify(operand1.m_double_value - static_cast(operand2.m_int_value)) != FP_ZERO); + + return CommonExpressionValue(0); + } + + if (operand1.m_type == CommonExpressionValue::Type::INT) + { + if (operand2.m_type == CommonExpressionValue::Type::DOUBLE) + return CommonExpressionValue(std::fpclassify(operand1.m_double_value - operand2.m_double_value) != FP_ZERO); + if (operand2.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(operand1.m_int_value != operand2.m_int_value); + + return CommonExpressionValue(0); + } + + if (operand1.m_type == CommonExpressionValue::Type::STRING) + { + if (operand2.m_type == CommonExpressionValue::Type::STRING) + return CommonExpressionValue(*operand1.m_string_value != *operand2.m_string_value); + + return CommonExpressionValue(0); + } + + return CommonExpressionValue(0); + } +); + +const CommonExpressionBinaryOperationType CommonExpressionBinaryOperationType::OPERATION_AND( + "&&", + OperationPrecedence::LOGICAL_AND, + [](const CommonExpressionValue& operand1, const CommonExpressionValue& operand2) -> CommonExpressionValue + { + if (operand1.IsTruthy()) + return operand2; + return operand1; + } +); + +const CommonExpressionBinaryOperationType CommonExpressionBinaryOperationType::OPERATION_OR( + "||", + OperationPrecedence::LOGICAL_OR, + [](const CommonExpressionValue& operand1, const CommonExpressionValue& operand2) -> CommonExpressionValue + { + if (operand1.IsTruthy()) + return operand1; + return operand2; + } +); + +CommonExpressionBinaryOperation::CommonExpressionBinaryOperation(std::unique_ptr operand1, std::unique_ptr operand2, + const CommonExpressionBinaryOperationType* operationType) + : m_operand1(std::move(operand1)), + m_operand2(std::move(operand2)), + m_operation_type(operationType) +{ +} + +bool CommonExpressionBinaryOperation::Operand1NeedsParenthesis() const +{ + const auto* operation = dynamic_cast(m_operand1.get()); + return operation && operation->m_operation_type->m_precedence > m_operation_type->m_precedence; +} + +bool CommonExpressionBinaryOperation::Operand2NeedsParenthesis() const +{ + const auto* operation = dynamic_cast(m_operand2.get()); + return operation && operation->m_operation_type->m_precedence > m_operation_type->m_precedence; +} + +bool CommonExpressionBinaryOperation::IsStatic() +{ + assert(m_operand1 && m_operand2); + + return m_operand1->IsStatic() && m_operand2->IsStatic(); +} + +CommonExpressionValue CommonExpressionBinaryOperation::Evaluate() +{ + return m_operation_type->m_evaluation_function(m_operand1->Evaluate(), m_operand2->Evaluate()); +} diff --git a/src/ObjLoading/Parsing/Menu/Domain/Expression/CommonExpressionBinaryOperation.h b/src/ObjLoading/Parsing/Menu/Domain/Expression/CommonExpressionBinaryOperation.h new file mode 100644 index 00000000..9393a67a --- /dev/null +++ b/src/ObjLoading/Parsing/Menu/Domain/Expression/CommonExpressionBinaryOperation.h @@ -0,0 +1,76 @@ +#pragma once + +#include +#include +#include + +#include "ICommonExpression.h" +#include "CommonExpressionValue.h" + +namespace menu +{ + // https://en.cppreference.com/w/cpp/language/operator_precedence + enum class OperationPrecedence + { + MULTIPLICATION_DIVISION_REMAINDER = 1, + ADDITION_SUBTRACTION = 2, + BITWISE_SHIFT = 3, + RELATIONAL_GREATER_LESS_THAN = 4, + RELATIONAL_EQUALS = 5, + BITWISE_AND = 6, + BITWISE_OR = 8, + LOGICAL_AND = 9, + LOGICAL_OR = 10 + }; + + class CommonExpressionBinaryOperationType + { + public: + using evaluation_function_t = std::function; + + std::string m_syntax; + OperationPrecedence m_precedence; + evaluation_function_t m_evaluation_function; + + private: + CommonExpressionBinaryOperationType(std::string syntax, OperationPrecedence precedence, evaluation_function_t evaluationFunction); + + static const CommonExpressionBinaryOperationType OPERATION_ADD; + static const CommonExpressionBinaryOperationType OPERATION_SUBTRACT; + static const CommonExpressionBinaryOperationType OPERATION_MULTIPLY; + static const CommonExpressionBinaryOperationType OPERATION_DIVIDE; + static const CommonExpressionBinaryOperationType OPERATION_REMAINDER; + static const CommonExpressionBinaryOperationType OPERATION_BITWISE_AND; + static const CommonExpressionBinaryOperationType OPERATION_BITWISE_OR; + static const CommonExpressionBinaryOperationType OPERATION_SHIFT_LEFT; + static const CommonExpressionBinaryOperationType OPERATION_SHIFT_RIGHT; + static const CommonExpressionBinaryOperationType OPERATION_GREATER_THAN; + static const CommonExpressionBinaryOperationType OPERATION_GREATER_EQUAL_THAN; + static const CommonExpressionBinaryOperationType OPERATION_LESS_THAN; + static const CommonExpressionBinaryOperationType OPERATION_LESS_EQUAL_THAN; + static const CommonExpressionBinaryOperationType OPERATION_EQUALS; + static const CommonExpressionBinaryOperationType OPERATION_NOT_EQUAL; + static const CommonExpressionBinaryOperationType OPERATION_AND; + static const CommonExpressionBinaryOperationType OPERATION_OR; + + static const CommonExpressionBinaryOperationType* const ALL_OPERATION_TYPES[]; + }; + + class CommonExpressionBinaryOperation final : public ICommonExpression + { + public: + std::unique_ptr m_operand1; + std::unique_ptr m_operand2; + const CommonExpressionBinaryOperationType* m_operation_type; + + CommonExpressionBinaryOperation(std::unique_ptr operand1, + std::unique_ptr operand2, + const CommonExpressionBinaryOperationType* operationType); + + _NODISCARD bool Operand1NeedsParenthesis() const; + _NODISCARD bool Operand2NeedsParenthesis() const; + + bool IsStatic() override; + CommonExpressionValue Evaluate() override; + }; +} diff --git a/src/ObjLoading/Parsing/Menu/Domain/Expression/CommonExpressionFunctionCall.cpp b/src/ObjLoading/Parsing/Menu/Domain/Expression/CommonExpressionFunctionCall.cpp new file mode 100644 index 00000000..614393d0 --- /dev/null +++ b/src/ObjLoading/Parsing/Menu/Domain/Expression/CommonExpressionFunctionCall.cpp @@ -0,0 +1,18 @@ +#include "CommonExpressionFunctionCall.h" + +using namespace menu; + +CommonExpressionFunctionCall::CommonExpressionFunctionCall(std::string functionName) + : m_function_name(std::move(functionName)) +{ +} + +bool CommonExpressionFunctionCall::IsStatic() +{ + return false; +} + +CommonExpressionValue CommonExpressionFunctionCall::Evaluate() +{ + return CommonExpressionValue(0); +} diff --git a/src/ObjLoading/Parsing/Menu/Domain/Expression/CommonExpressionFunctionCall.h b/src/ObjLoading/Parsing/Menu/Domain/Expression/CommonExpressionFunctionCall.h new file mode 100644 index 00000000..ca7e88c6 --- /dev/null +++ b/src/ObjLoading/Parsing/Menu/Domain/Expression/CommonExpressionFunctionCall.h @@ -0,0 +1,19 @@ +#pragma once +#include + +#include "ICommonExpression.h" + +namespace menu +{ + class CommonExpressionFunctionCall final : public ICommonExpression + { + public: + std::string m_function_name; + std::vector> m_args; + + explicit CommonExpressionFunctionCall(std::string functionName); + + bool IsStatic() override; + CommonExpressionValue Evaluate() override; + }; +} diff --git a/src/ObjLoading/Parsing/Menu/Domain/Expression/CommonExpressionUnaryOperation.cpp b/src/ObjLoading/Parsing/Menu/Domain/Expression/CommonExpressionUnaryOperation.cpp new file mode 100644 index 00000000..67275a7d --- /dev/null +++ b/src/ObjLoading/Parsing/Menu/Domain/Expression/CommonExpressionUnaryOperation.cpp @@ -0,0 +1,55 @@ +#include "CommonExpressionUnaryOperation.h" + +#include + +#include "CommonExpressionBinaryOperation.h" + +using namespace menu; + +CommonExpressionUnaryOperationType::CommonExpressionUnaryOperationType(std::string syntax, evaluation_function_t evaluationFunction) + : m_syntax(std::move(syntax)), + m_evaluation_function(std::move(evaluationFunction)) +{ +} + +const CommonExpressionUnaryOperationType CommonExpressionUnaryOperationType::OPERATION_NOT( + "!", + [](const CommonExpressionValue& operand) -> CommonExpressionValue + { + return CommonExpressionValue(!operand.IsTruthy()); + } +); + +const CommonExpressionUnaryOperationType CommonExpressionUnaryOperationType::OPERATION_BITWISE_NOT( + "~", + [](const CommonExpressionValue& operand) -> CommonExpressionValue + { + if(operand.m_type == CommonExpressionValue::Type::INT) + return CommonExpressionValue(~operand.m_int_value); + + return CommonExpressionValue(0); + } +); + +CommonExpressionUnaryOperation::CommonExpressionUnaryOperation(std::unique_ptr operand, const CommonExpressionUnaryOperationType* operationType) + : m_operand(std::move(operand)), + m_operation_type(operationType) +{ +} + +bool CommonExpressionUnaryOperation::OperandNeedsParenthesis() const +{ + return dynamic_cast(m_operand.get()) != nullptr; +} + +bool CommonExpressionUnaryOperation::IsStatic() +{ + assert(m_operand); + + return m_operand->IsStatic(); +} + +CommonExpressionValue CommonExpressionUnaryOperation::Evaluate() +{ + return m_operation_type->m_evaluation_function(m_operand->Evaluate()); +} diff --git a/src/ObjLoading/Parsing/Menu/Domain/Expression/CommonExpressionUnaryOperation.h b/src/ObjLoading/Parsing/Menu/Domain/Expression/CommonExpressionUnaryOperation.h new file mode 100644 index 00000000..40288045 --- /dev/null +++ b/src/ObjLoading/Parsing/Menu/Domain/Expression/CommonExpressionUnaryOperation.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include +#include + +#include "ICommonExpression.h" +#include "CommonExpressionValue.h" + +namespace menu +{ + class CommonExpressionUnaryOperationType + { + public: + using evaluation_function_t = std::function; + + std::string m_syntax; + evaluation_function_t m_evaluation_function; + + private: + CommonExpressionUnaryOperationType(std::string syntax, evaluation_function_t evaluationFunction); + + static const CommonExpressionUnaryOperationType OPERATION_NOT; + static const CommonExpressionUnaryOperationType OPERATION_BITWISE_NOT; + + static const CommonExpressionUnaryOperationType* const ALL_OPERATION_TYPES[]; + }; + + class CommonExpressionUnaryOperation final : public ICommonExpression + { + public: + std::unique_ptr m_operand; + const CommonExpressionUnaryOperationType* m_operation_type; + + CommonExpressionUnaryOperation(std::unique_ptr operand, + const CommonExpressionUnaryOperationType* operationType); + + _NODISCARD bool OperandNeedsParenthesis() const; + + bool IsStatic() override; + CommonExpressionValue Evaluate() override; + }; +} diff --git a/src/ObjLoading/Parsing/Menu/Domain/Expression/CommonExpressionValue.cpp b/src/ObjLoading/Parsing/Menu/Domain/Expression/CommonExpressionValue.cpp new file mode 100644 index 00000000..b0735886 --- /dev/null +++ b/src/ObjLoading/Parsing/Menu/Domain/Expression/CommonExpressionValue.cpp @@ -0,0 +1,48 @@ +#include "CommonExpressionValue.h" + +#include + +using namespace menu; + +CommonExpressionValue::CommonExpressionValue(std::string stringValue) + : m_type(Type::STRING), + m_string_value(std::make_shared(std::move(stringValue))) +{ + m_double_value = 0; + m_int_value = 0; +} + +CommonExpressionValue::CommonExpressionValue(const double doubleValue) + : m_type(Type::DOUBLE) +{ + m_int_value = 0; + m_double_value = doubleValue; +} + +CommonExpressionValue::CommonExpressionValue(const int intValue) + : m_type(Type::INT) +{ + m_double_value = 0; + m_int_value = intValue; +} + +bool CommonExpressionValue::IsStatic() +{ + return true; +} + +CommonExpressionValue CommonExpressionValue::Evaluate() +{ + return *this; +} + +bool CommonExpressionValue::IsTruthy() const +{ + if (m_type == Type::DOUBLE) + return std::fpclassify(m_double_value) != FP_ZERO; + if (m_type == Type::INT) + return m_int_value != 0; + if (m_type == Type::STRING) + return m_string_value && !m_string_value->empty(); + return false; +} diff --git a/src/ObjLoading/Parsing/Menu/Domain/Expression/CommonExpressionValue.h b/src/ObjLoading/Parsing/Menu/Domain/Expression/CommonExpressionValue.h new file mode 100644 index 00000000..819ae94b --- /dev/null +++ b/src/ObjLoading/Parsing/Menu/Domain/Expression/CommonExpressionValue.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include + +#include "ICommonExpression.h" +#include "Utils/ClassUtils.h" + +namespace menu +{ + class ICommonExpression; + class CommonExpressionValue final : public ICommonExpression + { + public: + enum class Type + { + STRING, + DOUBLE, + INT + }; + + Type m_type; + std::shared_ptr m_string_value; + union + { + double m_double_value; + int m_int_value; + }; + + explicit CommonExpressionValue(std::string stringValue); + explicit CommonExpressionValue(double doubleValue); + explicit CommonExpressionValue(int intValue); + + bool IsStatic() override; + CommonExpressionValue Evaluate() override; + _NODISCARD bool IsTruthy() const; + }; +} diff --git a/src/ObjLoading/Parsing/Menu/Domain/Expression/ICommonExpression.h b/src/ObjLoading/Parsing/Menu/Domain/Expression/ICommonExpression.h new file mode 100644 index 00000000..4d8448e1 --- /dev/null +++ b/src/ObjLoading/Parsing/Menu/Domain/Expression/ICommonExpression.h @@ -0,0 +1,23 @@ +#pragma once + +namespace menu +{ + class CommonExpressionValue; + class ICommonExpression + { + protected: + ICommonExpression() = default; + public: + virtual ~ICommonExpression() = default; + ICommonExpression(const ICommonExpression& other) = default; + ICommonExpression(ICommonExpression&& other) noexcept = default; + ICommonExpression& operator=(const ICommonExpression& other) = default; + ICommonExpression& operator=(ICommonExpression&& other) noexcept = default; + + virtual bool IsStatic() = 0; + virtual CommonExpressionValue Evaluate() = 0; + }; +} + +// Include CommonExpressionValue after definition to avoid "base class not defined" +#include "CommonExpressionValue.h" \ No newline at end of file