#ifndef PORYGONLANG_BOUNDEXPRESSION_HPP #define PORYGONLANG_BOUNDEXPRESSION_HPP #include #include #include #include "../../ScriptTypes/ScriptType.hpp" #include "../BoundOperators.hpp" #include "../BoundVariables/BoundVariableKey.hpp" #include "../../Utilities/StringUtils.hpp" #include "../../UserData/UserDataOperation.hpp" using namespace std; namespace Porygon::Binder { enum class BoundExpressionKind : uint8_t { Bad, LiteralInteger, LiteralFloat, LiteralString, LiteralBool, Nil, Variable, Unary, Binary, UserdataBinary, FunctionCall, Index, PeriodIndex, NumericalTable, Table, Require, Cast, }; class BoundExpression { private: const unsigned int _start; const unsigned int _length; const shared_ptr _type; protected: inline void DrawIndents(std::stringstream& stream, size_t indents) const{ for (size_t i = 0; i < indents; i++) stream << "\t"; } public: BoundExpression(unsigned int start, unsigned int length, shared_ptr type) : _start(start), _length(length), _type(std::move(type)) { } virtual ~BoundExpression() = default; [[nodiscard]] virtual BoundExpressionKind GetKind() const = 0; [[nodiscard]] virtual const std::shared_ptr &GetType() const { return _type; }; [[nodiscard]] inline unsigned int GetStartPosition() const { return _start; } [[nodiscard]] inline unsigned int GetLength() const { return _length; } virtual void GetTreeString(std::stringstream& stream, size_t indents) const = 0; }; class BoundBadExpression : public BoundExpression { public: BoundBadExpression(unsigned int start, unsigned int length) : BoundExpression(start, length, make_shared( TypeClass::Error)) {} [[nodiscard]] inline BoundExpressionKind GetKind() const final { return BoundExpressionKind::Bad; } void GetTreeString(std::stringstream& stream, size_t indents) const final{ DrawIndents(stream, indents); stream << "BadExpression"; } }; class BoundLiteralIntegerExpression : public BoundExpression { const int64_t _value; public: BoundLiteralIntegerExpression(int64_t value, unsigned int start, unsigned int length) : BoundExpression(start, length, NumericScriptType::AwareInt), _value(value) { } [[nodiscard]] inline BoundExpressionKind GetKind() const final { return BoundExpressionKind::LiteralInteger; } [[nodiscard]] inline int64_t GetValue() const { return _value; } void GetTreeString(std::stringstream& stream, size_t indents) const final{ DrawIndents(stream, indents); stream << "LiteralInteger: " << _value << " (" << GetType()->ToString() << ")"; } }; class BoundLiteralFloatExpression : public BoundExpression { const double _value; public: BoundLiteralFloatExpression(double value, unsigned int start, unsigned int length) : BoundExpression(start, length, NumericScriptType::AwareFloat), _value(value) { } [[nodiscard]] inline BoundExpressionKind GetKind() const final { return BoundExpressionKind::LiteralFloat; } [[nodiscard]] inline double GetValue() const { return _value; } void GetTreeString(std::stringstream& stream, size_t indents) const final{ DrawIndents(stream, indents); stream << "LiteralFloat: " << _value << " (" << GetType()->ToString() << ")"; } }; class BoundLiteralStringExpression : public BoundExpression { const u16string _value; public: BoundLiteralStringExpression(const u16string &value, unsigned int start, unsigned int length) : BoundExpression(start, length, make_shared(true, Utilities::HashedString::ConstHash(value.c_str()))), _value(value) { } [[nodiscard]] inline BoundExpressionKind GetKind() const final { return BoundExpressionKind::LiteralString; } [[nodiscard]] inline const u16string* GetValue() const { return &_value; } void GetTreeString(std::stringstream& stream, size_t indents) const final{ DrawIndents(stream, indents); stream << "LiteralString: \"" << Utilities::StringUtils::FromUTF8(_value) << "\" (" << GetType()->ToString() << ")"; } }; class BoundLiteralBoolExpression : public BoundExpression { const bool _value; public: BoundLiteralBoolExpression(bool value, unsigned int start, unsigned int length) : BoundExpression(start, length, ScriptType::BoolType), _value(value) { } [[nodiscard]] inline BoundExpressionKind GetKind() const final { return BoundExpressionKind::LiteralBool; } [[nodiscard]] inline bool GetValue() const { return _value; } void GetTreeString(std::stringstream& stream, size_t indents) const final{ DrawIndents(stream, indents); stream << "LiteralBool: " << _value << " (" << GetType()->ToString() << ")"; } }; class BoundNilExpression : public BoundExpression { public: BoundNilExpression(unsigned int start, unsigned int length) : BoundExpression(start, length, ScriptType::NilType) { } [[nodiscard]] inline BoundExpressionKind GetKind() const final { return BoundExpressionKind::Nil; } void GetTreeString(std::stringstream& stream, size_t indents) const final{ DrawIndents(stream, indents); stream << "NilExpression" << " (" << GetType()->ToString() << ")"; } }; class BoundVariableExpression : public BoundExpression { const BoundVariableKey *_key; public: BoundVariableExpression(BoundVariableKey *key, const shared_ptr& type, unsigned int start, unsigned int length) : BoundExpression(start, length, type), _key(key) { } ~BoundVariableExpression() override { delete _key; } [[nodiscard]] inline BoundExpressionKind GetKind() const final { return BoundExpressionKind::Variable; } [[nodiscard]] inline const BoundVariableKey *GetKey() const { return _key; } void GetTreeString(std::stringstream& stream, size_t indents) const final{ DrawIndents(stream, indents); stream << "VariableExpression: " << _key->GetIdentifier()->GetDebugString() << " (" << GetType()->ToString() << ")"; } }; class BoundBinaryExpression : public BoundExpression { const BoundExpression *_left; const BoundExpression *_right; const BoundBinaryOperation _operation; public: BoundBinaryExpression(BoundExpression *left, BoundExpression *right, BoundBinaryOperation op, shared_ptr result, unsigned int start, unsigned int length) : BoundExpression(start, length, std::move(result)), _left(left), _right(right), _operation(op) { } ~BoundBinaryExpression() final { delete _left; delete _right; } [[nodiscard]] inline BoundExpressionKind GetKind() const final { return BoundExpressionKind::Binary; } [[nodiscard]] inline const BoundExpression *GetLeft() const { return _left; } [[nodiscard]] inline const BoundExpression *GetRight() const { return _right; } [[nodiscard]] inline BoundBinaryOperation GetOperation() const { return _operation; } 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::Equality: return "equality"; case BoundBinaryOperation::Inequality: return "inequality"; case BoundBinaryOperation::LessThan: return "lessThan"; case BoundBinaryOperation::LessThanEquals: return "lessThanEquals"; case BoundBinaryOperation::GreaterThan: return "greaterThan"; case BoundBinaryOperation::GreaterThanEquals: return "greaterThanEquals"; case BoundBinaryOperation::LogicalAnd: return "logicalAnd"; case BoundBinaryOperation::LogicalOr: return "logicalOr"; case BoundBinaryOperation::Concatenation: return "concatenation"; } throw exception(); } void GetTreeString(std::stringstream& stream, size_t indents) const final{ DrawIndents(stream, indents); stream << "BinaryExpression: " << GetOperationString(_operation) << " (" << GetType()->ToString() << ")" << endl; _left->GetTreeString(stream, indents + 1); stream << endl; _right->GetTreeString(stream, indents + 1); } }; class BoundUserdataBinaryExpression : public BoundExpression{ private: const BoundExpression* _left; const BoundExpression* _right; const UserData::UserDataBinaryOperation* _operation; public: BoundUserdataBinaryExpression(BoundExpression *left, BoundExpression *right, const UserData::UserDataBinaryOperation* op, shared_ptr result, unsigned int start, unsigned int length) : BoundExpression(start, length, std::move(result)), _left(left), _right(right), _operation(op) {} [[nodiscard]] inline const BoundExpression* GetLeft() const { return _left; } [[nodiscard]] inline const BoundExpression* GetRight() const { return _right; } [[nodiscard]] inline const UserData::UserDataBinaryOperation* GetOperation() const { return _operation; } [[nodiscard]] inline BoundExpressionKind GetKind() const final { return BoundExpressionKind::UserdataBinary; } void GetTreeString(std::stringstream& stream, size_t indents) const final { DrawIndents(stream, indents); stream << "BinaryExpression: " << "Userdata operand " << " (" << GetType()->ToString() << ")" << endl; _left->GetTreeString(stream, indents + 1); stream << endl; _right->GetTreeString(stream, indents + 1); } }; class BoundUnaryExpression : public BoundExpression { const BoundExpression *_operand; const BoundUnaryOperation _operation; public: BoundUnaryExpression(BoundExpression *operand, BoundUnaryOperation op, shared_ptr result, unsigned int start, unsigned int length) : BoundExpression(start, length, std::move(result)), _operand(operand), _operation(op) { } ~BoundUnaryExpression() final { delete _operand; } [[nodiscard]] inline BoundExpressionKind GetKind() const final { return BoundExpressionKind::Unary; } [[nodiscard]] inline const BoundExpression *GetOperand() const { return _operand; } [[nodiscard]] inline BoundUnaryOperation GetOperation() const { return _operation; } static std::string GetOperationString(BoundUnaryOperation op){ switch (op){ case BoundUnaryOperation::Negation: return "negation"; case BoundUnaryOperation::LogicalNegation: return "logicalNegation"; } throw exception(); } void GetTreeString(std::stringstream& stream, size_t indents) const final{ DrawIndents(stream, indents); stream << "UnaryExpression: " << GetOperationString(_operation) << " (" << GetType()->ToString() << ")" << endl; _operand->GetTreeString(stream, indents + 1); } }; class BoundIndexExpression : public BoundExpression { const BoundExpression *_indexableExpression; const BoundExpression *_indexExpression; public: BoundIndexExpression(BoundExpression *indexableExpression, BoundExpression *indexExpression, shared_ptr result, unsigned int start, unsigned int length) : BoundExpression(start, length, std::move(result)), _indexableExpression(indexableExpression), _indexExpression(indexExpression) {} ~BoundIndexExpression() final { delete _indexableExpression; delete _indexExpression; } [[nodiscard]] inline BoundExpressionKind GetKind() const final { return BoundExpressionKind::Index; } [[nodiscard]] inline const BoundExpression *GetIndexableExpression() const { return _indexableExpression; } [[nodiscard]] inline const BoundExpression *GetIndexExpression() const { return _indexExpression; } void GetTreeString(std::stringstream& stream, size_t indents) const final{ DrawIndents(stream, indents); stream << "IndexExpression" << " (" << GetType()->ToString() << ")" << endl; _indexableExpression->GetTreeString(stream, indents + 1); stream << endl; _indexExpression->GetTreeString(stream, indents + 1); } }; class BoundPeriodIndexExpression : public BoundExpression { const BoundExpression *_indexableExpression; const Utilities::HashedString _index; public: BoundPeriodIndexExpression(BoundExpression *indexableExpression, const Utilities::HashedString& index, shared_ptr result, unsigned int start, unsigned int length) : BoundExpression(start, length, std::move(result)), _indexableExpression(indexableExpression), _index(index) {} ~BoundPeriodIndexExpression() final { delete _indexableExpression; } [[nodiscard]] inline BoundExpressionKind GetKind() const final { return BoundExpressionKind::PeriodIndex; } [[nodiscard]] inline const BoundExpression *GetIndexableExpression() const { return _indexableExpression; } [[nodiscard]] inline const Utilities::HashedString* GetIndex() const { return &_index; } void GetTreeString(std::stringstream& stream, size_t indents) const final{ DrawIndents(stream, indents); stream << "PeriodIndex: " << _index.GetDebugString() << " (" << GetType()->ToString() << ")" << endl; _indexableExpression->GetTreeString(stream, indents + 1); } }; class BoundNumericalTableExpression : public BoundExpression { const vector _expressions; public: BoundNumericalTableExpression(vector expressions, shared_ptr type, unsigned int start, unsigned int length) : BoundExpression(start, length, std::move(type)), _expressions(std::move(expressions)) {} ~BoundNumericalTableExpression() final { for (auto e: _expressions) { delete e; } } [[nodiscard]] inline BoundExpressionKind GetKind() const final { return BoundExpressionKind::NumericalTable; } [[nodiscard]] inline const vector *GetExpressions() const { return &_expressions; } void GetTreeString(std::stringstream& stream, size_t indents) const final{ for (size_t i = 0; i < indents; i++) stream << "\t"; stream << "NumericalTable" << " (" << GetType()->ToString() << ")"; for (auto _expression : _expressions){ stream << endl; _expression->GetTreeString(stream, indents + 1); } } }; class BoundCastExpression : public BoundExpression { const BoundExpression* _expression; public: BoundCastExpression(BoundExpression* expression, shared_ptr castType) : BoundExpression(expression->GetStartPosition(), expression->GetLength(), castType), _expression(expression) {} [[nodiscard]] const BoundExpression* GetExpression() const{ return _expression; } ~BoundCastExpression() final { delete _expression; } [[nodiscard]] inline BoundExpressionKind GetKind() const final { return BoundExpressionKind::Cast; } void GetTreeString(std::stringstream& stream, size_t indents) const final{ for (size_t i = 0; i < indents; i++) stream << "\t"; stream << "CastExpression" << " (" << GetType()->ToString() << ")" << endl; _expression->GetTreeString(stream, indents + 1); } }; } #endif //PORYGONLANG_BOUNDEXPRESSION_HPP