diff --git a/src/Binder/BoundStatements/BoundStatement.hpp b/src/Binder/BoundStatements/BoundStatement.hpp index ce61d7e..143c336 100644 --- a/src/Binder/BoundStatements/BoundStatement.hpp +++ b/src/Binder/BoundStatements/BoundStatement.hpp @@ -27,6 +27,11 @@ namespace Porygon::Binder { }; class BoundStatement { + protected: + inline void DrawIndents(std::stringstream& stream, size_t indents) const{ + for (size_t i = 0; i < indents; i++) + stream << "\t"; + } public: [[nodiscard]] virtual BoundStatementKind GetKind() const = 0; @@ -58,8 +63,7 @@ namespace Porygon::Binder { } void GetTreeString(std::stringstream& stream, size_t indents) const final{ - for (size_t i = 0; i < indents; i++) - stream << "\t"; + DrawIndents(stream, indents); stream << "BreakStatement"; } }; @@ -88,8 +92,7 @@ namespace Porygon::Binder { } void GetTreeString(std::stringstream& stream, size_t indents) const override{ - for (size_t i = 0; i < indents; i++) - stream << "\t"; + DrawIndents(stream, indents); stream << "BlockStatement"; for (auto s : _statements){ stream << endl; @@ -140,8 +143,7 @@ namespace Porygon::Binder { } void GetTreeString(std::stringstream& stream, size_t indents) const override{ - for (size_t i = 0; i < indents; i++) - stream << "\t"; + DrawIndents(stream, indents); stream << "ExpressionStatement" << endl; _expression->GetTreeString(stream, indents + 1); } @@ -176,9 +178,8 @@ namespace Porygon::Binder { } void GetTreeString(std::stringstream& stream, size_t indents) const override{ - for (size_t i = 0; i < indents; i++) - stream << "\t"; - stream << "Assignment -> " << _key->GetIdentifier()->GetString() << endl; + DrawIndents(stream, indents); + stream << "Assignment -> " << _key->GetIdentifier()->GetDebugString() << endl; _expression->GetTreeString(stream, indents + 1); } }; @@ -212,8 +213,7 @@ namespace Porygon::Binder { } void GetTreeString(std::stringstream& stream, size_t indents) const override{ - for (size_t i = 0; i < indents; i++) - stream << "\t"; + DrawIndents(stream, indents); stream << "IndexAssignment" << endl; _indexExpression->GetTreeString(stream, indents + 1); stream << endl; @@ -243,10 +243,10 @@ namespace Porygon::Binder { } void GetTreeString(std::stringstream& stream, size_t indents) const override{ - for (size_t i = 0; i < indents; i++) - stream << "\t"; - stream << "ReturnStatement" << endl; + DrawIndents(stream, indents); + stream << "ReturnStatement"; if (_expression != nullptr){ + stream << endl; _expression->GetTreeString(stream, indents + 1); } } @@ -289,20 +289,18 @@ namespace Porygon::Binder { } void GetTreeString(std::stringstream& stream, size_t indents) const override{ - for (size_t i = 0; i < indents; i++) - stream << "\t"; + DrawIndents(stream, indents); stream << "ConditionalStatement" << endl; - for (size_t i = 0; i < indents; i++) - stream << "\t"; + DrawIndents(stream, indents); stream << "Condition:" << endl; _condition->GetTreeString(stream, indents + 1); - for (size_t i = 0; i < indents; i++) - stream << "\t"; + stream << endl; + DrawIndents(stream, indents); stream << "If True:" << endl; _block->GetTreeString(stream, indents + 1); if (_elseStatement != nullptr){ - for (size_t i = 0; i < indents; i++) - stream << "\t"; + stream << endl; + DrawIndents(stream, indents); stream << "Else:" << endl; _elseStatement->GetTreeString(stream, indents + 1); } @@ -362,25 +360,23 @@ namespace Porygon::Binder { } void GetTreeString(std::stringstream& stream, size_t indents) const override{ - for (size_t i = 0; i < indents; i++) - stream << "\t"; + DrawIndents(stream, indents); stream << "NumericForLoopStatement" << endl; - for (size_t i = 0; i < indents; i++) - stream << "\t"; + DrawIndents(stream, indents); stream << "Start:" << endl; _start->GetTreeString(stream, indents + 1); - for (size_t i = 0; i < indents; i++) - stream << "\t"; + stream << endl; + DrawIndents(stream, indents); stream << "End:" << endl; _end->GetTreeString(stream, indents + 1); if (_step != nullptr){ - for (size_t i = 0; i < indents; i++) - stream << "\t"; + stream << endl; + DrawIndents(stream, indents); stream << "Step:" << endl; _step->GetTreeString(stream, indents + 1); } - for (size_t i = 0; i < indents; i++) - stream << "\t"; + stream << endl; + DrawIndents(stream, indents); stream << "Do:" << endl; _block->GetTreeString(stream, indents + 1); } @@ -432,18 +428,18 @@ namespace Porygon::Binder { } void GetTreeString(std::stringstream& stream, size_t indents) const override{ - for (size_t i = 0; i < indents; i++) - stream << "\t"; + DrawIndents(stream, indents); stream << "GenericForLoopStatement" << endl; - for (size_t i = 0; i < indents; i++) - stream << "\t"; - stream << "Key: " << _keyIdentifier->GetIdentifier()->GetString().get() << endl; - for (size_t i = 0; i < indents; i++) - stream << "\t"; - stream << "Value: " << _valueIdentifier->GetIdentifier()->GetString().get() << endl; - stream << "Iterator: " << endl; + DrawIndents(stream, indents); + stream << "Key: " << _keyIdentifier->GetIdentifier()->GetDebugString() << endl; + DrawIndents(stream, indents); + stream << "Value: " << _valueIdentifier->GetIdentifier()->GetDebugString() << endl; + DrawIndents(stream, indents); + stream << "Iterator:" << endl; _iterator->GetTreeString(stream, indents + 1); stream << endl; + DrawIndents(stream, indents); + stream << "Do:" << endl; _block->GetTreeString(stream, indents + 1); } }; @@ -477,15 +473,13 @@ namespace Porygon::Binder { } void GetTreeString(std::stringstream& stream, size_t indents) const override{ - for (size_t i = 0; i < indents; i++) - stream << "\t"; - stream << "ConditionalStatement" << endl; - for (size_t i = 0; i < indents; i++) - stream << "\t"; + DrawIndents(stream, indents); + stream << "WhileStatement" << endl; + DrawIndents(stream, indents); stream << "Condition:" << endl; _condition->GetTreeString(stream, indents + 1); - for (size_t i = 0; i < indents; i++) - stream << "\t"; + stream << endl; + DrawIndents(stream, indents); stream << "While True:" << endl; _block->GetTreeString(stream, indents + 1); } diff --git a/src/Utilities/HashedString.hpp b/src/Utilities/HashedString.hpp index 1d0ea28..0147cf1 100644 --- a/src/Utilities/HashedString.hpp +++ b/src/Utilities/HashedString.hpp @@ -4,6 +4,7 @@ #include #include +#include "StringUtils.hpp" namespace Porygon::Utilities{ class HashedString{ @@ -51,6 +52,13 @@ namespace Porygon::Utilities{ return _string; } + inline const std::string GetDebugString() const{ + if (_string){ + return Utilities::StringUtils::FromUTF8(*_string.get()); + } + return std::to_string(_hash); + } + inline bool operator==(const HashedString& b) const{ return _hash == b._hash; } diff --git a/tests/TreeStringTests.cpp b/tests/TreeStringTests.cpp index 482d184..1e6291d 100644 --- a/tests/TreeStringTests.cpp +++ b/tests/TreeStringTests.cpp @@ -3,7 +3,9 @@ #include #include "../src/Binder/BoundStatements/BoundStatement.hpp" +#include "../src/Utilities/HashedString.hpp" using namespace Porygon::Binder; +using namespace Porygon::Utilities; TEST_CASE( "Bad Statement To String", "[BoundTreeString]" ) { std::stringstream stream; @@ -29,4 +31,118 @@ TEST_CASE( "Block Statement To String", "[BoundTreeString]" ) { delete s; } +TEST_CASE( "Expression Statement To String", "[BoundTreeString]" ) { + std::stringstream stream; + auto s = new BoundExpressionStatement(new BoundNilExpression(0,0)); + s->GetTreeString(stream, 1); + REQUIRE(stream.str() == "\tExpressionStatement\n\t\tNilExpression (nil)"); + delete s; +} + +TEST_CASE( "Assignment Statement To String", "[BoundTreeString]" ) { + std::stringstream stream; + auto key = new u16string(u"key"); + const BoundVariableKey *keyObj = new BoundVariableKey(HashedString(key), 0, true); + auto s = new BoundAssignmentStatement(keyObj, new BoundLiteralIntegerExpression(5, 0,0)); + s->GetTreeString(stream, 1); + REQUIRE(stream.str() == "\tAssignment -> key\n\t\tLiteralInteger: 5 (number)"); + delete s; +} + +TEST_CASE( "Index Assignment Statement To String", "[BoundTreeString]" ) { + std::stringstream stream; + auto s = new BoundIndexAssignmentStatement(new BoundNilExpression(0,0), new BoundNilExpression(0,0)); + s->GetTreeString(stream, 1); + REQUIRE(stream.str() == "\tIndexAssignment\n\t\tNilExpression (nil)\n\t\tNilExpression (nil)"); + delete s; +} + +TEST_CASE( "Return Statement with expression To String", "[BoundTreeString]" ) { + std::stringstream stream; + auto s = new BoundReturnStatement(new BoundNilExpression(0,0)); + s->GetTreeString(stream, 1); + REQUIRE(stream.str() == "\tReturnStatement\n\t\tNilExpression (nil)"); + delete s; +} + +TEST_CASE( "Return Statement without expression To String", "[BoundTreeString]" ) { + std::stringstream stream; + auto s = new BoundReturnStatement(nullptr); + s->GetTreeString(stream, 1); + REQUIRE(stream.str() == "\tReturnStatement"); + delete s; +} + +TEST_CASE( "Conditional To String", "[BoundTreeString]" ) { + std::stringstream stream; + auto s = new BoundConditionalStatement(new BoundLiteralBoolExpression(true,0,0), + new BoundBadStatement(), new BoundBadStatement()); + s->GetTreeString(stream, 1); + REQUIRE(stream.str() == + R"( ConditionalStatement + Condition: + LiteralBool: 1 (bool) + If True: + BadStatement + Else: + BadStatement)"); + delete s; +} + +TEST_CASE( "Numerical For to String", "[BoundTreeString]" ) { + std::stringstream stream; + auto key = new u16string(u"i"); + const BoundVariableKey *keyObj = new BoundVariableKey(HashedString(key), 0, true); + auto s = new BoundNumericalForStatement(keyObj, new BoundLiteralIntegerExpression(0,0,0), + new BoundLiteralIntegerExpression(5,0,0), + new BoundLiteralIntegerExpression(1,0,0), + new BoundBadStatement()); + s->GetTreeString(stream, 1); + REQUIRE(stream.str() == + R"( NumericForLoopStatement + Start: + LiteralInteger: 0 (number) + End: + LiteralInteger: 5 (number) + Step: + LiteralInteger: 1 (number) + Do: + BadStatement)"); + delete s; +} + +TEST_CASE( "Generic For to String", "[BoundTreeString]" ) { + std::stringstream stream; + auto key = new u16string(u"k"); + const BoundVariableKey *keyObj = new BoundVariableKey(HashedString(key), 0, true); + auto valueKey = new u16string(u"v"); + const BoundVariableKey *valueKeyObj = new BoundVariableKey(HashedString(valueKey), 0, true); + auto s = new BoundGenericForStatement(keyObj, valueKeyObj, new BoundNilExpression(0,0), new BoundBadStatement()); + s->GetTreeString(stream, 1); + REQUIRE(stream.str() == + R"( GenericForLoopStatement + Key: k + Value: v + Iterator: + NilExpression (nil) + Do: + BadStatement)"); + delete s; +} + +TEST_CASE( "While To String", "[BoundTreeString]" ) { + std::stringstream stream; + auto s = new BoundWhileStatement(new BoundLiteralBoolExpression(true,0,0), + new BoundBadStatement()); + s->GetTreeString(stream, 1); + REQUIRE(stream.str() == + R"( WhileStatement + Condition: + LiteralBool: 1 (bool) + While True: + BadStatement)"); + delete s; +} + + #endif \ No newline at end of file