From 3f08be0564b383991d97b21e7763a93a1d23166b Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 14 Feb 2021 10:27:18 +0100 Subject: [PATCH] Add stream proxy for declaring pack values --- .../Parsing/Header/HeaderFileReader.cpp | 7 +- .../Parsing/Header/HeaderFileReader.h | 2 + .../Parsing/IPackValueSupplier.h | 14 +++ .../Impl/PackDefinitionStreamProxy.cpp | 92 +++++++++++++++++++ .../Parsing/Impl/PackDefinitionStreamProxy.h | 35 +++++++ .../Impl/PackDefinitionStreamProxyTests.cpp | 39 ++++++++ 6 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 src/ZoneCodeGeneratorLib/Parsing/IPackValueSupplier.h create mode 100644 src/ZoneCodeGeneratorLib/Parsing/Impl/PackDefinitionStreamProxy.cpp create mode 100644 src/ZoneCodeGeneratorLib/Parsing/Impl/PackDefinitionStreamProxy.h create mode 100644 test/ZoneCodeGeneratorLibTests/Parsing/Impl/PackDefinitionStreamProxyTests.cpp diff --git a/src/ZoneCodeGeneratorLib/Parsing/Header/HeaderFileReader.cpp b/src/ZoneCodeGeneratorLib/Parsing/Header/HeaderFileReader.cpp index 457acf4c..1767097e 100644 --- a/src/ZoneCodeGeneratorLib/Parsing/Header/HeaderFileReader.cpp +++ b/src/ZoneCodeGeneratorLib/Parsing/Header/HeaderFileReader.cpp @@ -8,11 +8,13 @@ #include "Parsing/Impl/CommentRemovingStreamProxy.h" #include "Parsing/Impl/DefinesStreamProxy.h" #include "Parsing/Impl/IncludingStreamProxy.h" +#include "Parsing/Impl/PackDefinitionStreamProxy.h" #include "Parsing/Impl/ParserFilesystemStream.h" HeaderFileReader::HeaderFileReader(const ZoneCodeGeneratorArguments* args, std::string filename) : m_args(args), m_filename(std::move(filename)), + m_pack_value_supplier(nullptr), m_stream(nullptr) { } @@ -35,13 +37,16 @@ void HeaderFileReader::SetupStreamProxies() { auto commentProxy = std::make_unique(m_stream); auto includeProxy = std::make_unique(commentProxy.get()); - auto definesProxy = std::make_unique(includeProxy.get()); + auto packProxy = std::make_unique(includeProxy.get()); + auto definesProxy = std::make_unique(packProxy.get()); definesProxy->AddDefine(ZONE_CODE_GENERATOR_DEFINE_NAME, ZONE_CODE_GENERATOR_DEFINE_VALUE); + m_pack_value_supplier = packProxy.get(); m_stream = definesProxy.get(); m_open_streams.emplace_back(std::move(commentProxy)); m_open_streams.emplace_back(std::move(includeProxy)); + m_open_streams.emplace_back(std::move(packProxy)); m_open_streams.emplace_back(std::move(definesProxy)); } diff --git a/src/ZoneCodeGeneratorLib/Parsing/Header/HeaderFileReader.h b/src/ZoneCodeGeneratorLib/Parsing/Header/HeaderFileReader.h index 7a8f5d1f..bd9e848d 100644 --- a/src/ZoneCodeGeneratorLib/Parsing/Header/HeaderFileReader.h +++ b/src/ZoneCodeGeneratorLib/Parsing/Header/HeaderFileReader.h @@ -3,6 +3,7 @@ #include #include "ZoneCodeGeneratorArguments.h" +#include "Parsing/IPackValueSupplier.h" #include "Parsing/IParserLineStream.h" #include "Persistence/IDataRepository.h" @@ -15,6 +16,7 @@ class HeaderFileReader std::string m_filename; std::vector> m_open_streams; + IPackValueSupplier* m_pack_value_supplier; IParserLineStream* m_stream; bool OpenBaseStream(); diff --git a/src/ZoneCodeGeneratorLib/Parsing/IPackValueSupplier.h b/src/ZoneCodeGeneratorLib/Parsing/IPackValueSupplier.h new file mode 100644 index 00000000..6edde9fb --- /dev/null +++ b/src/ZoneCodeGeneratorLib/Parsing/IPackValueSupplier.h @@ -0,0 +1,14 @@ +#pragma once + +class IPackValueSupplier +{ +public: + IPackValueSupplier() = default; + virtual ~IPackValueSupplier() = default; + IPackValueSupplier(const IPackValueSupplier& other) = default; + IPackValueSupplier(IPackValueSupplier&& other) noexcept = default; + IPackValueSupplier& operator=(const IPackValueSupplier& other) = default; + IPackValueSupplier& operator=(IPackValueSupplier&& other) noexcept = default; + + virtual int GetCurrentPack() = 0; +}; \ No newline at end of file diff --git a/src/ZoneCodeGeneratorLib/Parsing/Impl/PackDefinitionStreamProxy.cpp b/src/ZoneCodeGeneratorLib/Parsing/Impl/PackDefinitionStreamProxy.cpp new file mode 100644 index 00000000..8694f9f7 --- /dev/null +++ b/src/ZoneCodeGeneratorLib/Parsing/Impl/PackDefinitionStreamProxy.cpp @@ -0,0 +1,92 @@ +#include "PackDefinitionStreamProxy.h" + +#include "Parsing/ParsingException.h" + +PackDefinitionStreamProxy::PackDefinitionStreamProxy(IParserLineStream* stream) + : m_stream(stream) +{ +} + +bool PackDefinitionStreamProxy::MatchPackDirective(const ParserLine& line, unsigned directivePosition) +{ + auto packValue = 0; + + if (!MatchString(line, directivePosition, PRAGMA_PACK_DIRECTIVE, std::char_traits::length(PRAGMA_PACK_DIRECTIVE))) + return false; + + if (!MatchNextCharacter(line, directivePosition, '(')) + throw ParsingException(CreatePos(line, directivePosition), "Invalid pack directive."); + + bool isPush; + if (MatchNextString(line, directivePosition, PUSH_KEYWORD, std::char_traits::length(PUSH_KEYWORD))) + isPush = true; + else if (MatchNextString(line, directivePosition, POP_KEYWORD, std::char_traits::length(POP_KEYWORD))) + isPush = false; + else + throw ParsingException(CreatePos(line, directivePosition), "Unknown pack directive command."); + + if(isPush) + { + if (!MatchNextCharacter(line, directivePosition, ',')) + throw ParsingException(CreatePos(line, directivePosition), "Invalid pack directive."); + + if (!ExtractInteger(line, directivePosition, packValue)) + throw ParsingException(CreatePos(line, directivePosition), "Invalid pack value."); + } + + if (!MatchNextCharacter(line, directivePosition, ')')) + throw ParsingException(CreatePos(line, directivePosition), "Invalid pack directive."); + + if(isPush) + m_current_pack.push(packValue); + else if (!m_current_pack.empty()) + m_current_pack.pop(); + + return true; +} + +bool PackDefinitionStreamProxy::MatchDirectives(const ParserLine& line) +{ + unsigned directivePos; + + if (!FindDirective(line, directivePos)) + return false; + + directivePos++; + return MatchPackDirective(line, directivePos); +} + +ParserLine PackDefinitionStreamProxy::NextLine() +{ + auto line = m_stream->NextLine(); + + while (MatchDirectives(line)) + line = m_stream->NextLine(); + + return line; +} + +bool PackDefinitionStreamProxy::IncludeFile(const std::string& filename) +{ + return m_stream->IncludeFile(filename); +} + +void PackDefinitionStreamProxy::PopCurrentFile() +{ + m_stream->PopCurrentFile(); +} + +bool PackDefinitionStreamProxy::IsOpen() const +{ + return m_stream->IsOpen(); +} + +bool PackDefinitionStreamProxy::Eof() const +{ + return m_stream->Eof(); +} + +int PackDefinitionStreamProxy::GetCurrentPack() +{ + return m_current_pack.empty() ? DEFAULT_PACK : m_current_pack.top(); +} diff --git a/src/ZoneCodeGeneratorLib/Parsing/Impl/PackDefinitionStreamProxy.h b/src/ZoneCodeGeneratorLib/Parsing/Impl/PackDefinitionStreamProxy.h new file mode 100644 index 00000000..fd50b61b --- /dev/null +++ b/src/ZoneCodeGeneratorLib/Parsing/Impl/PackDefinitionStreamProxy.h @@ -0,0 +1,35 @@ +#pragma once + +#include + +#include "AbstractDirectiveStreamProxy.h" +#include "Parsing/IPackValueSupplier.h" +#include "Parsing/IParserLineStream.h" + +class PackDefinitionStreamProxy final : public AbstractDirectiveStreamProxy, public IPackValueSupplier +{ +public: + static constexpr int DEFAULT_PACK = 8; + +private: + static constexpr const char* PRAGMA_PACK_DIRECTIVE = "pragma pack"; + static constexpr const char* PUSH_KEYWORD = "push"; + static constexpr const char* POP_KEYWORD = "pop"; + + IParserLineStream* const m_stream; + std::stack m_current_pack; + + _NODISCARD bool MatchPackDirective(const ParserLine& line, unsigned directivePosition); + _NODISCARD bool MatchDirectives(const ParserLine& line); + +public: + explicit PackDefinitionStreamProxy(IParserLineStream* stream); + + ParserLine NextLine() override; + bool IncludeFile(const std::string& filename) override; + void PopCurrentFile() override; + _NODISCARD bool IsOpen() const override; + _NODISCARD bool Eof() const override; + + int GetCurrentPack() override; +}; diff --git a/test/ZoneCodeGeneratorLibTests/Parsing/Impl/PackDefinitionStreamProxyTests.cpp b/test/ZoneCodeGeneratorLibTests/Parsing/Impl/PackDefinitionStreamProxyTests.cpp new file mode 100644 index 00000000..def2f9e7 --- /dev/null +++ b/test/ZoneCodeGeneratorLibTests/Parsing/Impl/PackDefinitionStreamProxyTests.cpp @@ -0,0 +1,39 @@ +#include + +#include "Parsing/Impl/PackDefinitionStreamProxy.h" +#include "Parsing/Mock/MockParserLineStream.h" + +namespace test::parsing::impl::pack_definition_stream_proxy +{ + void ExpectLine(IParserLineStream* stream, const int lineNumber, const std::string& value) + { + auto line = stream->NextLine(); + REQUIRE(line.m_line_number == lineNumber); + REQUIRE(line.m_line == value); + } + + TEST_CASE("PackDefinitionStreamProxy: Ensure simple pack directives are working", "[parsing][parsingstream]") + { + const std::vector lines + { + "hello world", + "#pragma pack(push, 32)", + "hello galaxy", + "#pragma pack(pop)", + "hello universe" + }; + + MockParserLineStream mockStream(lines); + PackDefinitionStreamProxy proxy(&mockStream); + + REQUIRE(proxy.GetCurrentPack() == PackDefinitionStreamProxy::DEFAULT_PACK); + ExpectLine(&proxy, 1, "hello world"); + REQUIRE(proxy.GetCurrentPack() == PackDefinitionStreamProxy::DEFAULT_PACK); + ExpectLine(&proxy, 3, "hello galaxy"); + REQUIRE(proxy.GetCurrentPack() == 32); + ExpectLine(&proxy, 5, "hello universe"); + REQUIRE(proxy.GetCurrentPack() == PackDefinitionStreamProxy::DEFAULT_PACK); + + REQUIRE(proxy.Eof()); + } +} \ No newline at end of file