#ifndef PORYGONLANG_NUMERICEVALVALUE_HPP #define PORYGONLANG_NUMERICEVALVALUE_HPP #include #include "EvalValue.hpp" #include "../../Utilities/StringUtils.hpp" namespace Porygon::Evaluation { class NumericEvalValue : public EvalValue { [[nodiscard]] virtual long GetIntegerValue() const = 0; [[nodiscard]] virtual double GetFloatValue() const = 0; public: [[nodiscard]] virtual bool IsFloat() const = 0; [[nodiscard]] inline TypeClass GetTypeClass() const final { return TypeClass::Number; } shared_ptr operator+(const shared_ptr &b) const; shared_ptr operator-(const shared_ptr &b) const; shared_ptr operator*(const shared_ptr &b) const; shared_ptr operator/(const shared_ptr &b) const; shared_ptr operator<(const shared_ptr &b) const; shared_ptr operator<=(const shared_ptr &b) const; shared_ptr operator>(const shared_ptr &b) const; shared_ptr operator>=(const shared_ptr &b) const; bool operator==(const EvalValue *b) const final; }; class IntegerEvalValue : public NumericEvalValue { const long _value; [[nodiscard]] long GetIntegerValue() const final { return _value; } [[nodiscard]] double GetFloatValue() const final { throw EvaluationException("Attempting to retrieve float from int eval value."); } public: explicit IntegerEvalValue(long value) : _value(value) { } [[nodiscard]] inline bool IsFloat() const final { return false; } [[nodiscard]] inline long EvaluateInteger() const final { return _value; } [[nodiscard]] inline std::u16string EvaluateString() const final{ return Utilities::StringUtils::IntToString(_value); } [[nodiscard]] inline EvalValue* Clone() const final { return new IntegerEvalValue(_value); } [[nodiscard]] inline std::size_t GetHashCode() const final { return std::hash{}(_value); } [[nodiscard]] EvalValue* BinaryOperation(Binder::BoundBinaryOperation operation, const EvalValue* b) const final; [[nodiscard]] EvalValue* UnaryOperation(Binder::BoundUnaryOperation operation) const final{ switch (operation){ case Binder::BoundUnaryOperation::Negation: return new IntegerEvalValue(-_value); default: throw; } } }; class FloatEvalValue : public NumericEvalValue { const double _value; [[nodiscard]] inline long GetIntegerValue() const final { throw EvaluationException("Attempting to retrieve float from int eval value."); } [[nodiscard]] inline double GetFloatValue() const final { return _value; } public: explicit FloatEvalValue(double value) : _value(value) { } [[nodiscard]] inline bool IsFloat() const final { return true; } [[nodiscard]] inline double EvaluateFloat() const final { return _value; } [[nodiscard]] inline EvalValue* Clone() const final { return new FloatEvalValue(_value); } [[nodiscard]] inline std::size_t GetHashCode() const final { return std::hash{}(_value); } [[nodiscard]] inline EvalValue* BinaryOperation(Binder::BoundBinaryOperation operation, const EvalValue* b) const final{ auto right = dynamic_cast(b); if (right->IsFloat()){ auto rightVal = right->EvaluateFloat(); switch (operation){ case Binder::BoundBinaryOperation::Addition: return new FloatEvalValue(_value + rightVal); case Binder::BoundBinaryOperation::Subtraction: return new FloatEvalValue(_value - rightVal); case Binder::BoundBinaryOperation::Multiplication: return new FloatEvalValue(_value * rightVal); case Binder::BoundBinaryOperation::Division: return new FloatEvalValue(_value / rightVal); case Binder::BoundBinaryOperation::LessThan: return new BooleanEvalValue(_value < rightVal); case Binder::BoundBinaryOperation::LessThanEquals: return new BooleanEvalValue(_value <= rightVal); case Binder::BoundBinaryOperation::GreaterThan: return new BooleanEvalValue(_value > rightVal); case Binder::BoundBinaryOperation::GreaterThanEquals: return new BooleanEvalValue(_value >= rightVal); default: throw; } } else { auto rightVal = right->EvaluateInteger(); switch (operation) { case Binder::BoundBinaryOperation::Addition: return new IntegerEvalValue((long) _value + rightVal); case Binder::BoundBinaryOperation::Subtraction: return new IntegerEvalValue((long) _value - rightVal); case Binder::BoundBinaryOperation::Multiplication: return new IntegerEvalValue((long) _value * rightVal); case Binder::BoundBinaryOperation::Division: return new IntegerEvalValue((long) _value / rightVal); case Binder::BoundBinaryOperation::LessThan: return new BooleanEvalValue(_value < rightVal); case Binder::BoundBinaryOperation::LessThanEquals: return new BooleanEvalValue(_value <= rightVal); case Binder::BoundBinaryOperation::GreaterThan: return new BooleanEvalValue(_value > rightVal); case Binder::BoundBinaryOperation::GreaterThanEquals: return new BooleanEvalValue(_value >= rightVal); default: throw; } } } [[nodiscard]] EvalValue* UnaryOperation(Binder::BoundUnaryOperation operation) const final{ switch (operation){ case Binder::BoundUnaryOperation::Negation: return new FloatEvalValue(-_value); default: throw; } } }; } #endif //PORYGONLANG_NUMERICEVALVALUE_HPP