#ifndef PORYGONLANG_SCRIPTTYPE_HPP #define PORYGONLANG_SCRIPTTYPE_HPP #include #include #include #include "../Utilities/HashedString.hpp" #include "CastResult.hpp" using namespace std; namespace Porygon{ enum class TypeClass{ Error, Nil, Number, Bool, String, Function, UserData, Table, Any, }; class ScriptType{ TypeClass _class; public: static shared_ptr BoolType; static shared_ptr NilType; static shared_ptr AnyType; explicit ScriptType(TypeClass c){ _class = c; } virtual ~ScriptType() = default; [[nodiscard]] inline TypeClass GetClass() const{ return _class; } virtual bool operator ==(const shared_ptr& b) const; virtual bool operator !=(const shared_ptr& b) const; virtual bool CanBeIndexedWith(const ScriptType* indexer) const; [[nodiscard]] virtual bool CanBeIndexedWithIdentifier(uint32_t hash) const; [[nodiscard]] virtual shared_ptr GetIndexedType(const ScriptType* indexer) const; [[nodiscard]] virtual shared_ptr GetIndexedType(uint32_t hash) const; [[nodiscard]] virtual bool CanBeIterated() const; [[nodiscard]] virtual shared_ptr GetIteratorKeyType() const; [[nodiscard]] virtual CastResult CastableTo(const shared_ptr& castType, bool explicitCast) const; static std::string ToString(TypeClass c); [[nodiscard]] virtual std::string ToString() const; }; class NumericScriptType : public ScriptType{ // Are we aware of whether this is a float or not? bool _awareOfFloat; // Is this value a float? bool _isFloat; public: static shared_ptr AwareInt; static shared_ptr AwareFloat; static shared_ptr Unaware; static shared_ptr ResolveType(bool isAware, bool isFloat){ if (isAware){ if (isFloat) return AwareFloat; return AwareInt; } return Unaware; } explicit NumericScriptType(bool floatAware, bool isFloat) : ScriptType(TypeClass::Number){ _awareOfFloat = floatAware; _isFloat = isFloat; } [[nodiscard]] inline bool IsAwareOfFloat() const{ return _awareOfFloat; } [[nodiscard]] inline bool IsFloat() const{ return _isFloat; } bool operator ==(const shared_ptr& b) const final{ if (b->GetClass() != TypeClass::Number) return false; auto bNum = dynamic_pointer_cast(b); if (bNum->IsAwareOfFloat() && IsAwareOfFloat()){ return bNum->IsFloat() == IsFloat(); } return true; }; bool operator !=(const shared_ptr& b) const final{ return ! (operator==(b)); } [[nodiscard]] CastResult CastableTo(const shared_ptr& castType, bool explicitCast) const final{ if (!explicitCast){ if (castType->GetClass() != TypeClass::Number ) return CastResult::InvalidCast; auto bNum = dynamic_pointer_cast(castType); if (bNum->IsFloat() && !IsFloat()) return CastResult::ValidCast; if (!bNum->IsFloat() && IsFloat()) return CastResult::DataLoss; } return ScriptType::CastableTo(castType, explicitCast); } }; class StringScriptType : public ScriptType{ bool _isKnownAtBind; uint32_t _hashValue; public: explicit StringScriptType(bool knownAtBind, uint32_t hashValue): ScriptType(TypeClass::String){ _isKnownAtBind = knownAtBind; _hashValue = hashValue; } static shared_ptr Dynamic; [[nodiscard]] bool CanBeIndexedWith(const ScriptType* indexer) const final{ if (indexer -> GetClass() != TypeClass::Number) return false; auto num = dynamic_cast(indexer); return !(num->IsAwareOfFloat() && num->IsFloat()); } inline shared_ptr GetIndexedType(const ScriptType* indexer) const final{ return StringScriptType::Dynamic; } [[nodiscard]] inline bool IsKnownAtBind() const{ return _isKnownAtBind; } [[nodiscard]] inline uint32_t GetHashValue() const{ return _hashValue; } }; class NumericalTableScriptType : public ScriptType{ shared_ptr _valueType; // Consider adding a check whether the table actually contains a type if every key is static. public: explicit NumericalTableScriptType(shared_ptr valueType) : ScriptType(TypeClass::Table), _valueType(std::move(valueType)){ } bool CanBeIndexedWith(const ScriptType* indexer) const final{ if (indexer -> GetClass() != TypeClass::Number) return false; auto num = dynamic_cast(indexer); return !(num->IsAwareOfFloat() && num->IsFloat()); } inline shared_ptr GetIndexedType(const ScriptType* indexer) const final{ return _valueType; } [[nodiscard]] inline bool CanBeIterated() const final{ return true; } [[nodiscard]] inline shared_ptr GetIteratorKeyType() const final{ return NumericScriptType::AwareInt; } }; } #endif //PORYGONLANG_SCRIPTTYPE_HPP