#ifndef PORYGONLANG_EVALVALUE_HPP #define PORYGONLANG_EVALVALUE_HPP #include #include #include #include "../../ScriptTypes/ScriptType.hpp" #include "../EvaluationException.hpp" namespace Porygon::Evaluation{ class EvalValue; class Iterator; } #include "../Iterator/Iterator.hpp" #include "../../Binder/BoundOperators.hpp" namespace Porygon::Evaluation { class EvalValue { public: EvalValue() = default; virtual ~EvalValue() = default; [[nodiscard]] virtual TypeClass GetTypeClass() const = 0; [[nodiscard]] virtual bool operator==(const EvalValue *b) const = 0; [[nodiscard]] virtual bool operator!=(const EvalValue *b) const = 0; [[nodiscard]] virtual EvalValue* Clone() const = 0; [[nodiscard]] virtual int64_t EvaluateInteger() const { throw EvaluationException("Can't evaluate this EvalValue as integer."); } [[nodiscard]] virtual double EvaluateFloat() const { throw EvaluationException("Can't evaluate this EvalValue as float."); } [[nodiscard]] virtual bool EvaluateBool() const { throw EvaluationException("Can't evaluate this EvalValue as bool."); } [[nodiscard]] virtual std::u16string EvaluateString() const { throw EvaluationException("Can't evaluate this EvalValue as string."); } [[nodiscard]] virtual std::size_t GetHashCode() const = 0; [[nodiscard]] virtual const EvalValue* IndexValue(const EvalValue *val) const { std::stringstream err; err << "Can't index this EvalValue: " << ToString() << " with key: " << val->ToString(); throw EvaluationException(err.str()); } [[nodiscard]] virtual const EvalValue* IndexValue(const Utilities::HashedString* hash) const { std::stringstream err; err << "Can't index this EvalValue: " << ToString() << " with key hash: " << hash->GetDebugString(); throw EvaluationException(err.str()); } virtual void SetIndexValue(const EvalValue *key, const EvalValue* value) const { std::stringstream err; err << "Can't index this EvalValue: " << ToString() << " with key: " << value->ToString(); throw EvaluationException(err.str()); } [[nodiscard]] virtual Iterator * GetKeyIterator() const{ throw EvaluationException("Can't iterate over this EvalValue"); } [[nodiscard]] virtual EvalValue* BinaryOperation(Binder::BoundBinaryOperation operation, const EvalValue* b) const{ throw EvaluationException("Binary operations are not implemented for this type."); } [[nodiscard]] virtual EvalValue* UnaryOperation(Binder::BoundUnaryOperation operation) const{ throw EvaluationException("Unary operations are not implemented for this type."); } [[nodiscard]] virtual EvalValue* Cast(shared_ptr castType) const{ throw new EvaluationException("Casting to invalid type."); } virtual std::string ToString() const{ std::stringstream s; s << "Type: " << ScriptType::ToString(this->GetTypeClass()); return s.str(); } }; class BooleanEvalValue : public EvalValue { const bool _value; public: explicit BooleanEvalValue(bool val) : _value(val) { } [[nodiscard]] inline EvalValue* Clone() const final { return new BooleanEvalValue(_value); } [[nodiscard]] inline TypeClass GetTypeClass() const final { return TypeClass::Bool; } [[nodiscard]] inline bool EvaluateBool() const final { return _value; } [[nodiscard]] bool operator==(const EvalValue *b) const final { if (b->GetTypeClass() != TypeClass::Bool) return false; return this->EvaluateBool() == b->EvaluateBool(); }; bool operator!=(const EvalValue *b) const override { return !operator==(b); } [[nodiscard]] inline std::size_t GetHashCode() const final { return _value; } [[nodiscard]] inline EvalValue* BinaryOperation(Binder::BoundBinaryOperation operation, const EvalValue* b) const final{ auto bVal = b -> EvaluateBool(); switch (operation){ case Binder::BoundBinaryOperation::LogicalAnd: return new BooleanEvalValue(_value && bVal); case Binder::BoundBinaryOperation::LogicalOr: return new BooleanEvalValue(_value || bVal); default: throw; } } [[nodiscard]] EvalValue* UnaryOperation(Binder::BoundUnaryOperation operation) const final{ switch (operation){ case Binder::BoundUnaryOperation::LogicalNegation: return new BooleanEvalValue(!_value); default: throw; } } }; } #endif //PORYGONLANG_EVALVALUE_HPP