OpenAssetTools/src/Parser/Parsing/Simple/Expression/SimpleExpressionBinaryOperation.cpp
2023-11-19 21:07:28 +00:00

455 lines
23 KiB
C++

#include "SimpleExpressionBinaryOperation.h"
#include <cassert>
#include <cmath>
SimpleExpressionBinaryOperationType::SimpleExpressionBinaryOperationType(const SimpleBinaryOperationId id,
std::string syntax,
const SimpleOperationPrecedence precedence,
evaluation_function_t evaluationFunction)
: m_id(id),
m_syntax(std::move(syntax)),
m_precedence(precedence),
m_evaluation_function(std::move(evaluationFunction))
{
}
const SimpleExpressionBinaryOperationType SimpleExpressionBinaryOperationType::OPERATION_ADD(
SimpleBinaryOperationId::ADD,
"+",
SimpleOperationPrecedence::ADDITION_SUBTRACTION,
[](const SimpleExpressionValue& operand1, const SimpleExpressionValue& operand2) -> SimpleExpressionValue
{
if (operand1.m_type == SimpleExpressionValue::Type::DOUBLE)
{
if (operand2.m_type == SimpleExpressionValue::Type::DOUBLE)
return SimpleExpressionValue(operand1.m_double_value + operand2.m_double_value);
if (operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(operand1.m_double_value + static_cast<double>(operand2.m_int_value));
if (operand2.m_type == SimpleExpressionValue::Type::STRING)
return SimpleExpressionValue(std::to_string(operand1.m_double_value) + *operand2.m_string_value);
}
else if (operand1.m_type == SimpleExpressionValue::Type::INT)
{
if (operand2.m_type == SimpleExpressionValue::Type::DOUBLE)
return SimpleExpressionValue(static_cast<double>(operand1.m_int_value) + operand2.m_double_value);
if (operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(operand1.m_int_value + operand2.m_int_value);
if (operand2.m_type == SimpleExpressionValue::Type::STRING)
return SimpleExpressionValue(std::to_string(operand1.m_int_value) + *operand2.m_string_value);
}
else if (operand1.m_type == SimpleExpressionValue::Type::STRING)
{
if (operand2.m_type == SimpleExpressionValue::Type::DOUBLE)
return SimpleExpressionValue(*operand1.m_string_value + std::to_string(operand2.m_double_value));
if (operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(*operand1.m_string_value + std::to_string(operand2.m_int_value));
if (operand2.m_type == SimpleExpressionValue::Type::STRING)
return SimpleExpressionValue(*operand1.m_string_value + *operand2.m_string_value);
}
return SimpleExpressionValue(0);
});
const SimpleExpressionBinaryOperationType SimpleExpressionBinaryOperationType::OPERATION_SUBTRACT(
SimpleBinaryOperationId::SUBTRACT,
"-",
SimpleOperationPrecedence::ADDITION_SUBTRACTION,
[](const SimpleExpressionValue& operand1, const SimpleExpressionValue& operand2) -> SimpleExpressionValue
{
if (operand1.m_type == SimpleExpressionValue::Type::DOUBLE)
{
if (operand2.m_type == SimpleExpressionValue::Type::DOUBLE)
return SimpleExpressionValue(operand1.m_double_value - operand2.m_double_value);
if (operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(operand1.m_double_value - static_cast<double>(operand2.m_int_value));
}
else if (operand1.m_type == SimpleExpressionValue::Type::INT)
{
if (operand2.m_type == SimpleExpressionValue::Type::DOUBLE)
return SimpleExpressionValue(static_cast<double>(operand1.m_int_value) - operand2.m_double_value);
if (operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(operand1.m_int_value - operand2.m_int_value);
}
return SimpleExpressionValue(0);
});
const SimpleExpressionBinaryOperationType SimpleExpressionBinaryOperationType::OPERATION_MULTIPLY(
SimpleBinaryOperationId::MULTIPLY,
"*",
SimpleOperationPrecedence::MULTIPLICATION_DIVISION_REMAINDER,
[](const SimpleExpressionValue& operand1, const SimpleExpressionValue& operand2) -> SimpleExpressionValue
{
if (operand1.m_type == SimpleExpressionValue::Type::DOUBLE)
{
if (operand2.m_type == SimpleExpressionValue::Type::DOUBLE)
return SimpleExpressionValue(operand1.m_double_value * operand2.m_double_value);
if (operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(operand1.m_double_value * static_cast<double>(operand2.m_int_value));
}
else if (operand1.m_type == SimpleExpressionValue::Type::INT)
{
if (operand2.m_type == SimpleExpressionValue::Type::DOUBLE)
return SimpleExpressionValue(static_cast<double>(operand1.m_int_value) * operand2.m_double_value);
if (operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(operand1.m_int_value * operand2.m_int_value);
}
return SimpleExpressionValue(0);
});
const SimpleExpressionBinaryOperationType SimpleExpressionBinaryOperationType::OPERATION_DIVIDE(
SimpleBinaryOperationId::DIVIDE,
"/",
SimpleOperationPrecedence::MULTIPLICATION_DIVISION_REMAINDER,
[](const SimpleExpressionValue& operand1, const SimpleExpressionValue& operand2) -> SimpleExpressionValue
{
if (operand1.m_type == SimpleExpressionValue::Type::DOUBLE)
{
if (operand2.m_type == SimpleExpressionValue::Type::DOUBLE)
return SimpleExpressionValue(operand1.m_double_value / operand2.m_double_value);
if (operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(operand1.m_double_value / static_cast<double>(operand2.m_int_value));
}
else if (operand1.m_type == SimpleExpressionValue::Type::INT)
{
if (operand2.m_type == SimpleExpressionValue::Type::DOUBLE)
return SimpleExpressionValue(static_cast<double>(operand1.m_int_value) / operand2.m_double_value);
if (operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(operand1.m_int_value / operand2.m_int_value);
}
return SimpleExpressionValue(0);
});
const SimpleExpressionBinaryOperationType SimpleExpressionBinaryOperationType::OPERATION_REMAINDER(
SimpleBinaryOperationId::REMAINDER,
"%",
SimpleOperationPrecedence::MULTIPLICATION_DIVISION_REMAINDER,
[](const SimpleExpressionValue& operand1, const SimpleExpressionValue& operand2) -> SimpleExpressionValue
{
if (operand1.m_type == SimpleExpressionValue::Type::INT && operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(operand1.m_int_value % operand2.m_int_value);
return SimpleExpressionValue(0);
});
const SimpleExpressionBinaryOperationType SimpleExpressionBinaryOperationType::OPERATION_BITWISE_AND(
SimpleBinaryOperationId::BITWISE_AND,
"&",
SimpleOperationPrecedence::BITWISE_AND,
[](const SimpleExpressionValue& operand1, const SimpleExpressionValue& operand2) -> SimpleExpressionValue
{
if (operand1.m_type == SimpleExpressionValue::Type::INT && operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(operand1.m_int_value & operand2.m_int_value);
return SimpleExpressionValue(0);
});
const SimpleExpressionBinaryOperationType SimpleExpressionBinaryOperationType::OPERATION_BITWISE_OR(
SimpleBinaryOperationId::BITWISE_OR,
"|",
SimpleOperationPrecedence::BITWISE_OR,
[](const SimpleExpressionValue& operand1, const SimpleExpressionValue& operand2) -> SimpleExpressionValue
{
if (operand1.m_type == SimpleExpressionValue::Type::INT && operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(operand1.m_int_value | operand2.m_int_value);
return SimpleExpressionValue(0);
});
const SimpleExpressionBinaryOperationType SimpleExpressionBinaryOperationType::OPERATION_SHIFT_LEFT(
SimpleBinaryOperationId::SHIFT_LEFT,
"<<",
SimpleOperationPrecedence::BITWISE_SHIFT,
[](const SimpleExpressionValue& operand1, const SimpleExpressionValue& operand2) -> SimpleExpressionValue
{
if (operand1.m_type == SimpleExpressionValue::Type::INT && operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(operand1.m_int_value << operand2.m_int_value);
return SimpleExpressionValue(0);
});
const SimpleExpressionBinaryOperationType SimpleExpressionBinaryOperationType::OPERATION_SHIFT_RIGHT(
SimpleBinaryOperationId::SHIFT_RIGHT,
">>",
SimpleOperationPrecedence::BITWISE_SHIFT,
[](const SimpleExpressionValue& operand1, const SimpleExpressionValue& operand2) -> SimpleExpressionValue
{
if (operand1.m_type == SimpleExpressionValue::Type::INT && operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(operand1.m_int_value >> operand2.m_int_value);
return SimpleExpressionValue(0);
});
const SimpleExpressionBinaryOperationType SimpleExpressionBinaryOperationType::OPERATION_GREATER_THAN(
SimpleBinaryOperationId::GREATER_THAN,
">",
SimpleOperationPrecedence::RELATIONAL_GREATER_LESS_THAN,
[](const SimpleExpressionValue& operand1, const SimpleExpressionValue& operand2) -> SimpleExpressionValue
{
if (operand1.m_type == SimpleExpressionValue::Type::STRING || operand2.m_type == SimpleExpressionValue::Type::STRING)
return SimpleExpressionValue(operand1.IsTruthy() > operand2.IsTruthy());
if (operand1.m_type == SimpleExpressionValue::Type::DOUBLE)
{
if (operand2.m_type == SimpleExpressionValue::Type::DOUBLE)
return SimpleExpressionValue(operand1.m_double_value > operand2.m_double_value);
if (operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(operand1.m_double_value > operand2.m_int_value);
}
else if (operand1.m_type == SimpleExpressionValue::Type::INT)
{
if (operand2.m_type == SimpleExpressionValue::Type::DOUBLE)
return SimpleExpressionValue(operand1.m_int_value > operand2.m_double_value);
if (operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(operand1.m_int_value > operand2.m_int_value);
}
return SimpleExpressionValue(0);
});
const SimpleExpressionBinaryOperationType SimpleExpressionBinaryOperationType::OPERATION_GREATER_EQUAL_THAN(
SimpleBinaryOperationId::GREATER_EQUAL_THAN,
">=",
SimpleOperationPrecedence::RELATIONAL_GREATER_LESS_THAN,
[](const SimpleExpressionValue& operand1, const SimpleExpressionValue& operand2) -> SimpleExpressionValue
{
if (operand1.m_type == SimpleExpressionValue::Type::STRING || operand2.m_type == SimpleExpressionValue::Type::STRING)
return SimpleExpressionValue(operand1.IsTruthy() >= operand2.IsTruthy());
if (operand1.m_type == SimpleExpressionValue::Type::DOUBLE)
{
if (operand2.m_type == SimpleExpressionValue::Type::DOUBLE)
return SimpleExpressionValue(operand1.m_double_value >= operand2.m_double_value);
if (operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(operand1.m_double_value >= operand2.m_int_value);
}
else if (operand1.m_type == SimpleExpressionValue::Type::INT)
{
if (operand2.m_type == SimpleExpressionValue::Type::DOUBLE)
return SimpleExpressionValue(operand1.m_int_value >= operand2.m_double_value);
if (operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(operand1.m_int_value >= operand2.m_int_value);
}
return SimpleExpressionValue(0);
});
const SimpleExpressionBinaryOperationType SimpleExpressionBinaryOperationType::OPERATION_LESS_THAN(
SimpleBinaryOperationId::LESS_THAN,
"<",
SimpleOperationPrecedence::RELATIONAL_GREATER_LESS_THAN,
[](const SimpleExpressionValue& operand1, const SimpleExpressionValue& operand2) -> SimpleExpressionValue
{
if (operand1.m_type == SimpleExpressionValue::Type::STRING || operand2.m_type == SimpleExpressionValue::Type::STRING)
return SimpleExpressionValue(operand1.IsTruthy() < operand2.IsTruthy());
if (operand1.m_type == SimpleExpressionValue::Type::DOUBLE)
{
if (operand2.m_type == SimpleExpressionValue::Type::DOUBLE)
return SimpleExpressionValue(operand1.m_double_value < operand2.m_double_value);
if (operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(operand1.m_double_value < operand2.m_int_value);
}
else if (operand1.m_type == SimpleExpressionValue::Type::INT)
{
if (operand2.m_type == SimpleExpressionValue::Type::DOUBLE)
return SimpleExpressionValue(operand1.m_int_value < operand2.m_double_value);
if (operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(operand1.m_int_value < operand2.m_int_value);
}
return SimpleExpressionValue(0);
});
const SimpleExpressionBinaryOperationType SimpleExpressionBinaryOperationType::OPERATION_LESS_EQUAL_THAN(
SimpleBinaryOperationId::LESS_EQUAL_THAN,
"<=",
SimpleOperationPrecedence::RELATIONAL_GREATER_LESS_THAN,
[](const SimpleExpressionValue& operand1, const SimpleExpressionValue& operand2) -> SimpleExpressionValue
{
if (operand1.m_type == SimpleExpressionValue::Type::STRING || operand2.m_type == SimpleExpressionValue::Type::STRING)
return SimpleExpressionValue(operand1.IsTruthy() <= operand2.IsTruthy());
if (operand1.m_type == SimpleExpressionValue::Type::DOUBLE)
{
if (operand2.m_type == SimpleExpressionValue::Type::DOUBLE)
return SimpleExpressionValue(operand1.m_double_value <= operand2.m_double_value);
if (operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(operand1.m_double_value <= operand2.m_int_value);
}
else if (operand1.m_type == SimpleExpressionValue::Type::INT)
{
if (operand2.m_type == SimpleExpressionValue::Type::DOUBLE)
return SimpleExpressionValue(operand1.m_int_value <= operand2.m_double_value);
if (operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(operand1.m_int_value <= operand2.m_int_value);
}
return SimpleExpressionValue(0);
});
const SimpleExpressionBinaryOperationType SimpleExpressionBinaryOperationType::OPERATION_EQUALS(
SimpleBinaryOperationId::EQUALS,
"==",
SimpleOperationPrecedence::RELATIONAL_EQUALS,
[](const SimpleExpressionValue& operand1, const SimpleExpressionValue& operand2) -> SimpleExpressionValue
{
if (operand1.m_type == SimpleExpressionValue::Type::DOUBLE)
{
if (operand2.m_type == SimpleExpressionValue::Type::DOUBLE)
return SimpleExpressionValue(std::fpclassify(operand1.m_double_value - operand2.m_double_value) == FP_ZERO);
if (operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(std::fpclassify(operand1.m_double_value - static_cast<double>(operand2.m_int_value)) == FP_ZERO);
return SimpleExpressionValue(0);
}
if (operand1.m_type == SimpleExpressionValue::Type::INT)
{
if (operand2.m_type == SimpleExpressionValue::Type::DOUBLE)
return SimpleExpressionValue(std::fpclassify(operand1.m_double_value - operand2.m_double_value) == FP_ZERO);
if (operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(operand1.m_int_value == operand2.m_int_value);
return SimpleExpressionValue(0);
}
if (operand1.m_type == SimpleExpressionValue::Type::STRING)
{
if (operand2.m_type == SimpleExpressionValue::Type::STRING)
return SimpleExpressionValue(*operand1.m_string_value == *operand2.m_string_value);
return SimpleExpressionValue(0);
}
return SimpleExpressionValue(0);
});
const SimpleExpressionBinaryOperationType SimpleExpressionBinaryOperationType::OPERATION_NOT_EQUAL(
SimpleBinaryOperationId::NOT_EQUAL,
"!=",
SimpleOperationPrecedence::RELATIONAL_EQUALS,
[](const SimpleExpressionValue& operand1, const SimpleExpressionValue& operand2) -> SimpleExpressionValue
{
if (operand1.m_type == SimpleExpressionValue::Type::DOUBLE)
{
if (operand2.m_type == SimpleExpressionValue::Type::DOUBLE)
return SimpleExpressionValue(std::fpclassify(operand1.m_double_value - operand2.m_double_value) != FP_ZERO);
if (operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(std::fpclassify(operand1.m_double_value - static_cast<double>(operand2.m_int_value)) != FP_ZERO);
return SimpleExpressionValue(0);
}
if (operand1.m_type == SimpleExpressionValue::Type::INT)
{
if (operand2.m_type == SimpleExpressionValue::Type::DOUBLE)
return SimpleExpressionValue(std::fpclassify(operand1.m_double_value - operand2.m_double_value) != FP_ZERO);
if (operand2.m_type == SimpleExpressionValue::Type::INT)
return SimpleExpressionValue(operand1.m_int_value != operand2.m_int_value);
return SimpleExpressionValue(0);
}
if (operand1.m_type == SimpleExpressionValue::Type::STRING)
{
if (operand2.m_type == SimpleExpressionValue::Type::STRING)
return SimpleExpressionValue(*operand1.m_string_value != *operand2.m_string_value);
return SimpleExpressionValue(0);
}
return SimpleExpressionValue(0);
});
const SimpleExpressionBinaryOperationType SimpleExpressionBinaryOperationType::OPERATION_AND(SimpleBinaryOperationId::AND,
"&&",
SimpleOperationPrecedence::LOGICAL_AND,
[](const SimpleExpressionValue& operand1,
const SimpleExpressionValue& operand2) -> SimpleExpressionValue
{
if (operand1.IsTruthy())
return operand2;
return operand1;
});
const SimpleExpressionBinaryOperationType SimpleExpressionBinaryOperationType::OPERATION_OR(SimpleBinaryOperationId::OR,
"||",
SimpleOperationPrecedence::LOGICAL_OR,
[](const SimpleExpressionValue& operand1,
const SimpleExpressionValue& operand2) -> SimpleExpressionValue
{
if (operand1.IsTruthy())
return operand1;
return operand2;
});
const SimpleExpressionBinaryOperationType* const SimpleExpressionBinaryOperationType::ALL_OPERATION_TYPES[static_cast<int>(SimpleBinaryOperationId::COUNT)]{
&OPERATION_ADD,
&OPERATION_SUBTRACT,
&OPERATION_MULTIPLY,
&OPERATION_DIVIDE,
&OPERATION_REMAINDER,
&OPERATION_BITWISE_AND,
&OPERATION_BITWISE_OR,
&OPERATION_SHIFT_LEFT,
&OPERATION_SHIFT_RIGHT,
&OPERATION_GREATER_THAN,
&OPERATION_GREATER_EQUAL_THAN,
&OPERATION_LESS_THAN,
&OPERATION_LESS_EQUAL_THAN,
&OPERATION_EQUALS,
&OPERATION_NOT_EQUAL,
&OPERATION_AND,
&OPERATION_OR,
};
SimpleExpressionBinaryOperation::SimpleExpressionBinaryOperation(const SimpleExpressionBinaryOperationType* operationType,
std::unique_ptr<ISimpleExpression> operand1,
std::unique_ptr<ISimpleExpression> operand2)
: m_operation_type(operationType),
m_operand1(std::move(operand1)),
m_operand2(std::move(operand2))
{
}
bool SimpleExpressionBinaryOperation::Operand1NeedsParenthesis() const
{
const auto* operation = dynamic_cast<const SimpleExpressionBinaryOperation*>(m_operand1.get());
return operation && operation->m_operation_type->m_precedence > m_operation_type->m_precedence;
}
bool SimpleExpressionBinaryOperation::Operand2NeedsParenthesis() const
{
const auto* operation = dynamic_cast<const SimpleExpressionBinaryOperation*>(m_operand2.get());
return operation && operation->m_operation_type->m_precedence > m_operation_type->m_precedence;
}
bool SimpleExpressionBinaryOperation::Equals(const ISimpleExpression* other) const
{
const auto* otherBinaryOperation = dynamic_cast<const SimpleExpressionBinaryOperation*>(other);
return otherBinaryOperation && m_operation_type->m_id == otherBinaryOperation->m_operation_type->m_id
&& m_operand1->Equals(otherBinaryOperation->m_operand1.get()) && m_operand2->Equals(otherBinaryOperation->m_operand2.get());
}
bool SimpleExpressionBinaryOperation::IsStatic() const
{
assert(m_operand1 && m_operand2);
return m_operand1->IsStatic() && m_operand2->IsStatic();
}
SimpleExpressionValue SimpleExpressionBinaryOperation::EvaluateStatic() const
{
return m_operation_type->m_evaluation_function(m_operand1->EvaluateStatic(), m_operand2->EvaluateStatic());
}
SimpleExpressionValue SimpleExpressionBinaryOperation::EvaluateNonStatic(const ISimpleExpressionScopeValues* scopeValues) const
{
return m_operation_type->m_evaluation_function(m_operand1->EvaluateNonStatic(scopeValues), m_operand2->EvaluateNonStatic(scopeValues));
}