diff --git a/src/Binder/Binder.cpp b/src/Binder/Binder.cpp index 01dfcf9..504073d 100644 --- a/src/Binder/Binder.cpp +++ b/src/Binder/Binder.cpp @@ -599,8 +599,15 @@ namespace Porygon::Binder { expression->GetStartPosition(), expression->GetLength()); } break; - default: + case UnaryOperatorKind::Count: + if (operandType->IsCountable()){ + return new BoundUnaryExpression(operand, BoundUnaryOperation::Count, + NumericScriptType::AwareInt, + expression->GetStartPosition(), expression->GetLength()); + } break; + default: + throw Exception("Unknown unary operator was called."); } this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::NoUnaryOperationFound, expression->GetStartPosition(), diff --git a/src/Binder/BoundOperators.hpp b/src/Binder/BoundOperators.hpp index 40389bb..ffb1d27 100644 --- a/src/Binder/BoundOperators.hpp +++ b/src/Binder/BoundOperators.hpp @@ -23,6 +23,7 @@ namespace Porygon::Binder { enum class BoundUnaryOperation { Negation, + Count, LogicalNegation, }; } diff --git a/src/Evaluator/EvalValues/NumericalTableEvalValue.cpp b/src/Evaluator/EvalValues/NumericalTableEvalValue.cpp index 8e46c27..50c9d46 100644 --- a/src/Evaluator/EvalValues/NumericalTableEvalValue.cpp +++ b/src/Evaluator/EvalValues/NumericalTableEvalValue.cpp @@ -1,5 +1,6 @@ #include "NumericalTableEvalValue.hpp" #include "../Iterator/NumericalKeyIterator.hpp" +#include "../../Utilities/Random.hpp" inline Porygon::Evaluation::Iterator *Porygon::Evaluation::NumericalTableEvalValue::GetKeyIterator() const { return new NumericalKeyIterator(this); @@ -7,6 +8,14 @@ inline Porygon::Evaluation::Iterator *Porygon::Evaluation::NumericalTableEvalVal Porygon::Evaluation::NumericalTableEvalValue::NumericalTableEvalValue(shared_ptr> table) : _table(std::move(table)), - _hash(rand()) + _hash(Utilities::Random::Get()) { } + +Porygon::Evaluation::EvalValue * +Porygon::Evaluation::NumericalTableEvalValue::UnaryOperation(Porygon::Binder::BoundUnaryOperation operation) const { + if (operation == Porygon::Binder::BoundUnaryOperation::Count){ + return new NumericEvalValue(static_cast(this->_table->size())); + } + return EvalValue::UnaryOperation(operation); +} diff --git a/src/Evaluator/EvalValues/NumericalTableEvalValue.hpp b/src/Evaluator/EvalValues/NumericalTableEvalValue.hpp index 9a5c1db..ff2112b 100644 --- a/src/Evaluator/EvalValues/NumericalTableEvalValue.hpp +++ b/src/Evaluator/EvalValues/NumericalTableEvalValue.hpp @@ -69,7 +69,9 @@ namespace Porygon::Evaluation { [[nodiscard]] inline shared_ptr> GetTable() const{ return _table; - }; + } + + EvalValue *UnaryOperation(Binder::BoundUnaryOperation operation) const override;; }; } diff --git a/src/Evaluator/EvalValues/StringEvalValue.hpp b/src/Evaluator/EvalValues/StringEvalValue.hpp index 5c3ef85..816524b 100644 --- a/src/Evaluator/EvalValues/StringEvalValue.hpp +++ b/src/Evaluator/EvalValues/StringEvalValue.hpp @@ -4,6 +4,7 @@ #include #include "EvalValue.hpp" +#include "NumericEvalValue.hpp" #include "../../Utilities/HashedString.hpp" using namespace std; @@ -68,6 +69,13 @@ namespace Porygon::Evaluation { auto str = stringStream.str(); return new StringEvalValue(str); } + + [[nodiscard]] EvalValue *UnaryOperation(Binder::BoundUnaryOperation operation) const override { + if (operation == Binder::BoundUnaryOperation ::Count){ + return new NumericEvalValue(static_cast(_value->size())); + } + return EvalValue::UnaryOperation(operation); + } }; } diff --git a/src/Evaluator/EvalValues/TableEvalValue.cpp b/src/Evaluator/EvalValues/TableEvalValue.cpp index 26f2495..2995a5b 100644 --- a/src/Evaluator/EvalValues/TableEvalValue.cpp +++ b/src/Evaluator/EvalValues/TableEvalValue.cpp @@ -1,6 +1,15 @@ #include "TableEvalValue.hpp" #include "../Iterator/SimpleKeyIterator.hpp" +#include "NumericEvalValue.hpp" inline Porygon::Evaluation::Iterator * Porygon::Evaluation::TableEvalValue::GetKeyIterator() const { return new TableKeyIterator(this); } + +Porygon::Evaluation::EvalValue * +Porygon::Evaluation::TableEvalValue::UnaryOperation(Porygon::Binder::BoundUnaryOperation operation) const { + if (operation == Porygon::Binder::BoundUnaryOperation::Count){ + return new NumericEvalValue(static_cast(this->_table->size())); + } + return EvalValue::UnaryOperation(operation); +} diff --git a/src/Evaluator/EvalValues/TableEvalValue.hpp b/src/Evaluator/EvalValues/TableEvalValue.hpp index a663099..843653f 100644 --- a/src/Evaluator/EvalValues/TableEvalValue.hpp +++ b/src/Evaluator/EvalValues/TableEvalValue.hpp @@ -83,7 +83,9 @@ namespace Porygon::Evaluation { [[nodiscard]] inline _Rb_tree_const_iterator> GetTableIteratorEnd() const{ return _table->cend(); - }; + } + + EvalValue *UnaryOperation(Binder::BoundUnaryOperation operation) const override;; }; } diff --git a/src/Parser/Lexer.cpp b/src/Parser/Lexer.cpp index 6b4badc..cb1022c 100644 --- a/src/Parser/Lexer.cpp +++ b/src/Parser/Lexer.cpp @@ -103,6 +103,8 @@ namespace Porygon::Parser { } this->ScriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UnexpectedCharacter, this->_position - 1, 1); return new SimpleToken(TokenKind::BadToken, this->_position - 1, 1); + case '#': + return new SimpleToken(TokenKind::HashToken, this->_position - 1, 1); case '0': case '1': case '2': diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index 5127286..cfcd631 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -362,6 +362,7 @@ namespace Porygon::Parser { switch (kind) { case TokenKind::PlusToken: case TokenKind::MinusToken: + case TokenKind::HashToken: case TokenKind::NotKeyword: return OperatorPrecedence::Unary; default: @@ -375,6 +376,8 @@ namespace Porygon::Parser { return UnaryOperatorKind::Identity; case TokenKind::MinusToken: return UnaryOperatorKind::Negation; + case TokenKind::HashToken : + return UnaryOperatorKind::Count; case TokenKind::NotKeyword: return UnaryOperatorKind::LogicalNegation; default: // This should never trigger, so throw. diff --git a/src/Parser/TokenKind.hpp b/src/Parser/TokenKind.hpp index b90503d..3ab41b9 100644 --- a/src/Parser/TokenKind.hpp +++ b/src/Parser/TokenKind.hpp @@ -19,6 +19,7 @@ namespace Porygon::Parser { LessEquals, Greater, GreaterEquals, + HashToken, OpenParenthesis, CloseParenthesis, diff --git a/src/Parser/UnaryOperatorKind.hpp b/src/Parser/UnaryOperatorKind.hpp index 305a42e..0a6818e 100644 --- a/src/Parser/UnaryOperatorKind.hpp +++ b/src/Parser/UnaryOperatorKind.hpp @@ -6,6 +6,7 @@ namespace Porygon::Parser { enum class UnaryOperatorKind { Identity, Negation, + Count, LogicalNegation, }; } diff --git a/src/ScriptTypes/ScriptType.cpp b/src/ScriptTypes/ScriptType.cpp index 786eedd..f2f731e 100644 --- a/src/ScriptTypes/ScriptType.cpp +++ b/src/ScriptTypes/ScriptType.cpp @@ -1,5 +1,7 @@ #include "../Script.hpp" #include "../UserData/UserDataFunctionType.hpp" +#include "ScriptType.hpp" + namespace Porygon{ inline bool ScriptType::CanBeIndexedWith(const ScriptType *) const{ @@ -76,6 +78,14 @@ namespace Porygon{ return ToString(this->_class); } + bool ScriptType::IsCountable() const { + return false; + } + + bool StringScriptType::IsCountable() const { + return true; + } + extern "C"{ ScriptType* CreateScriptType(Porygon::TypeClass t){ return new ScriptType(t); diff --git a/src/ScriptTypes/ScriptType.hpp b/src/ScriptTypes/ScriptType.hpp index 3d86141..059f311 100644 --- a/src/ScriptTypes/ScriptType.hpp +++ b/src/ScriptTypes/ScriptType.hpp @@ -51,6 +51,8 @@ namespace Porygon{ [[nodiscard]] virtual CastResult CastableTo(const shared_ptr& castType, bool explicitCast) const; + [[nodiscard]] virtual bool IsCountable() const; + static std::string ToString(TypeClass c); [[nodiscard]] virtual std::string ToString() const; }; @@ -145,6 +147,8 @@ namespace Porygon{ inline uint32_t GetHashValue() const{ return _hashValue; } + + bool IsCountable() const override; }; class NumericalTableScriptType : public ScriptType{ diff --git a/src/ScriptTypes/TableScriptType.hpp b/src/ScriptTypes/TableScriptType.hpp index 5c823ed..dccdd64 100644 --- a/src/ScriptTypes/TableScriptType.hpp +++ b/src/ScriptTypes/TableScriptType.hpp @@ -65,6 +65,10 @@ namespace Porygon{ shared_ptr GetIteratorKeyType() const final { return make_shared(TypeClass::Any); } + + bool IsCountable() const override { + return true; + } }; } diff --git a/src/UserData/UserDataCollections/UserDataCollectionType.hpp b/src/UserData/UserDataCollections/UserDataCollectionType.hpp index 396740a..3d791f7 100644 --- a/src/UserData/UserDataCollections/UserDataCollectionType.hpp +++ b/src/UserData/UserDataCollections/UserDataCollectionType.hpp @@ -20,7 +20,8 @@ namespace Porygon::UserData { _iterable(iterable) {} - static shared_ptr CreateIndexable(const shared_ptr& keyType, const shared_ptr& valueType){ + static shared_ptr CreateIndexable(const shared_ptr& keyType, + const shared_ptr& valueType){ return make_shared(keyType, valueType, true, true); } @@ -65,6 +66,10 @@ namespace Porygon::UserData { return _valueType; } } + + [[nodiscard]] bool IsCountable() const override { + return true; + } }; } diff --git a/src/UserData/UserDataCollections/UserDataCollectionValue.cpp b/src/UserData/UserDataCollections/UserDataCollectionValue.cpp index 894b47f..7873d9e 100644 --- a/src/UserData/UserDataCollections/UserDataCollectionValue.cpp +++ b/src/UserData/UserDataCollections/UserDataCollectionValue.cpp @@ -8,8 +8,9 @@ UserDataCollectionType* CreateCollectionType(const ScriptType* keyType, const Sc UserDataCollectionValue* CreateCollectionValue(UserDataCollectionType* type, void* obj, const EvalValue* (*get)(void*, const EvalValue*), void (*set)(void*, const EvalValue*, const EvalValue*), - Iterator* (*getIterator)(void*)){ - return new UserDataCollectionValue(shared_ptr(type), new UserDataCollectionHelper(obj, get, set, getIterator)); + Iterator* (*getIterator)(void*), size_t (getSize)(void*)){ + return new UserDataCollectionValue(shared_ptr(type), + new UserDataCollectionHelper(obj, get, set, getIterator, getSize)); } } } diff --git a/src/UserData/UserDataCollections/UserDataCollectionValue.hpp b/src/UserData/UserDataCollections/UserDataCollectionValue.hpp index 5ec7625..c027f40 100644 --- a/src/UserData/UserDataCollections/UserDataCollectionValue.hpp +++ b/src/UserData/UserDataCollections/UserDataCollectionValue.hpp @@ -6,6 +6,7 @@ #include "UserDataCollectionType.hpp" #include "../../Evaluator/EvalValues/EvalValue.hpp" #include "../../Utilities/Random.hpp" +#include "../../Evaluator/EvalValues/NumericEvalValue.hpp" using namespace Porygon::Evaluation; @@ -15,12 +16,14 @@ namespace Porygon::UserData { const EvalValue* (*_get)(void*, const EvalValue*); void (*_set)(void*, const EvalValue* , const EvalValue*); Iterator* (*_getIterator)(void*); + size_t (*_getLength)(void*); public: UserDataCollectionHelper(void* parentObject, const EvalValue* (*get)(void*, const EvalValue*), void (*set)(void*, const EvalValue*, const EvalValue*), - Iterator* (*getIterator)(void*)) - : _parentObject(parentObject), _get(get), _set(set), _getIterator(getIterator){} + Iterator* (*getIterator)(void*), size_t (*getLength)(void*)) + : _parentObject(parentObject), _get(get), _set(set), _getIterator(getIterator), + _getLength(getLength){} const EvalValue* Get(const EvalValue* key) const{ return _get(_parentObject, key); @@ -33,6 +36,10 @@ namespace Porygon::UserData { [[nodiscard]] Iterator* GetIterator() const{ return _getIterator(_parentObject); } + + [[nodiscard]] size_t GetLength() const{ + return _getLength(_parentObject); + } }; class UserDataCollectionValue : public Evaluation::EvalValue{ @@ -46,7 +53,7 @@ namespace Porygon::UserData { } public: - UserDataCollectionValue(shared_ptr type, const UserDataCollectionHelper* helper) + UserDataCollectionValue(const shared_ptr& type, const UserDataCollectionHelper* helper) : _type(dynamic_pointer_cast(type)), _helper(helper), _hash(Utilities::Random::Get()) { } @@ -85,6 +92,13 @@ namespace Porygon::UserData { _helper->Set(key, value); delete value; } + + [[nodiscard]] EvalValue *UnaryOperation(Binder::BoundUnaryOperation operation) const override { + if (operation == Binder::BoundUnaryOperation::Count){ + return new NumericEvalValue(static_cast(_helper->GetLength())); + } + return EvalValue::UnaryOperation(operation); + } }; } diff --git a/src/UserData/UserDataTemplates.hpp b/src/UserData/UserDataTemplates.hpp index b1f9892..285e3ca 100644 --- a/src/UserData/UserDataTemplates.hpp +++ b/src/UserData/UserDataTemplates.hpp @@ -96,6 +96,8 @@ Porygon::Utilities::HashedString* Convert(const char* k){ auto val = ((T_USERDATA*)obj)->fieldName; \ auto size = val.size(); \ return new Porygon::UserData::UserDataCollectionRangeIterator(0, size); \ + }, [](void* obj) -> size_t{ \ + return ((T_USERDATA*)obj)->fieldName.size(); \ } \ ) \ ) \