From 03dd0f06b282f88ef91e854bd2a077271d266a71 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 6 Sep 2022 21:45:55 +0200 Subject: [PATCH] Add set define proxy to set a define based on an expression --- .../Templating/SetDefineStreamProxy.cpp | 100 ++++++++++++++++++ .../Templating/SetDefineStreamProxy.h | 31 ++++++ src/RawTemplater/Templating/Templater.cpp | 6 +- .../Templating/TemplatingStreamProxy.cpp | 2 +- .../Templating/TemplatingStreamProxy.h | 2 +- 5 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 src/RawTemplater/Templating/SetDefineStreamProxy.cpp create mode 100644 src/RawTemplater/Templating/SetDefineStreamProxy.h diff --git a/src/RawTemplater/Templating/SetDefineStreamProxy.cpp b/src/RawTemplater/Templating/SetDefineStreamProxy.cpp new file mode 100644 index 00000000..28531fd1 --- /dev/null +++ b/src/RawTemplater/Templating/SetDefineStreamProxy.cpp @@ -0,0 +1,100 @@ +#include "SetDefineStreamProxy.h" + +#include "Parsing/ParsingException.h" + +using namespace templating; + +SetDefineStreamProxy::SetDefineStreamProxy(IParserLineStream* stream) + : m_stream(stream), + m_defines_proxy(nullptr) +{ +} + +void SetDefineStreamProxy::SetDefinesProxy(DefinesStreamProxy* definesProxy) +{ + m_defines_proxy = definesProxy; +} + +bool SetDefineStreamProxy::MatchSetDirective(const ParserLine& line, const unsigned directiveStartPosition, const unsigned directiveEndPosition) const +{ + auto currentPosition = directiveStartPosition; + + if (directiveEndPosition - directiveStartPosition != std::char_traits::length(SET_DIRECTIVE) + || !MatchString(line, currentPosition, SET_DIRECTIVE, std::char_traits::length(SET_DIRECTIVE))) + { + return false; + } + + if (!SkipWhitespace(line, currentPosition)) + return false; + + const auto nameStartPosition = currentPosition; + if (!ExtractIdentifier(line, currentPosition)) + throw ParsingException(CreatePos(line, currentPosition), "Invalid set directive."); + + auto name = line.m_line.substr(nameStartPosition, currentPosition - nameStartPosition); + + if (!SkipWhitespace(line, currentPosition)) + throw ParsingException(CreatePos(line, currentPosition), "Invalid set directive."); + + const auto expressionString = line.m_line.substr(currentPosition, line.m_line.size() - currentPosition); + if (expressionString.empty()) + throw ParsingException(CreatePos(line, currentPosition), "Cannot set without an expression."); + + const auto expression = m_defines_proxy->ParseExpression(expressionString); + if (!expression) + throw ParsingException(CreatePos(line, currentPosition), "Failed to parse set expression"); + + if (!expression->IsStatic()) + throw ParsingException(CreatePos(line, currentPosition), "set expression must be static"); + + const auto value = expression->EvaluateStatic(); + + if (value.m_type != SimpleExpressionValue::Type::STRING) + throw ParsingException(CreatePos(line, currentPosition), "set expression must evaluate to string"); + + m_defines_proxy->AddDefine(DefinesStreamProxy::Define(std::move(name), *value.m_string_value)); + return true; +} + +bool SetDefineStreamProxy::MatchDirectives(const ParserLine& line) const +{ + unsigned directiveStartPos, directiveEndPos; + + if (!FindDirective(line, directiveStartPos, directiveEndPos)) + return false; + + directiveStartPos++; + + return MatchSetDirective(line, directiveStartPos, directiveEndPos); +} + +ParserLine SetDefineStreamProxy::NextLine() +{ + auto line = m_stream->NextLine(); + + while (MatchDirectives(line)) + line = m_stream->NextLine(); + + return line; +} + +bool SetDefineStreamProxy::IncludeFile(const std::string& filename) +{ + return m_stream->IncludeFile(filename); +} + +void SetDefineStreamProxy::PopCurrentFile() +{ + m_stream->PopCurrentFile(); +} + +bool SetDefineStreamProxy::IsOpen() const +{ + return m_stream->IsOpen(); +} + +bool SetDefineStreamProxy::Eof() const +{ + return m_stream->Eof(); +} diff --git a/src/RawTemplater/Templating/SetDefineStreamProxy.h b/src/RawTemplater/Templating/SetDefineStreamProxy.h new file mode 100644 index 00000000..70315a68 --- /dev/null +++ b/src/RawTemplater/Templating/SetDefineStreamProxy.h @@ -0,0 +1,31 @@ +#pragma once + +#include "Utils/ClassUtils.h" +#include "Parsing/Impl/AbstractDirectiveStreamProxy.h" +#include "Parsing/Impl/DefinesStreamProxy.h" + +namespace templating +{ + class SetDefineStreamProxy final : public AbstractDirectiveStreamProxy + { + public: + explicit SetDefineStreamProxy(IParserLineStream* stream); + + void SetDefinesProxy(DefinesStreamProxy* definesProxy); + + ParserLine NextLine() override; + bool IncludeFile(const std::string& filename) override; + void PopCurrentFile() override; + _NODISCARD bool IsOpen() const override; + _NODISCARD bool Eof() const override; + + private: + static constexpr const char* SET_DIRECTIVE = "set"; + + _NODISCARD bool MatchSetDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition) const; + _NODISCARD bool MatchDirectives(const ParserLine& line) const; + + IParserLineStream* const m_stream; + DefinesStreamProxy* m_defines_proxy; + }; +} diff --git a/src/RawTemplater/Templating/Templater.cpp b/src/RawTemplater/Templating/Templater.cpp index a0cb5235..5b9ec949 100644 --- a/src/RawTemplater/Templating/Templater.cpp +++ b/src/RawTemplater/Templating/Templater.cpp @@ -8,6 +8,7 @@ #include "Utils/ClassUtils.h" #include "DirectiveEscapeStreamProxy.h" +#include "SetDefineStreamProxy.h" #include "TemplatingStreamProxy.h" #include "Parsing/ParsingException.h" #include "Parsing/Impl/DefinesStreamProxy.h" @@ -32,16 +33,19 @@ namespace templating m_base_stream = std::make_unique(stream, fileName); m_templating_proxy = std::make_unique(m_base_stream.get(), templaterControl); - m_defines_proxy = std::make_unique(m_templating_proxy.get(), true); + m_set_define_proxy = std::make_unique(m_templating_proxy.get()); + m_defines_proxy = std::make_unique(m_set_define_proxy.get(), true); m_directive_escape_proxy = std::make_unique(m_defines_proxy.get()); m_skip_until_first_non_empty_proxy = std::make_unique(m_directive_escape_proxy.get()); m_templating_proxy->SetDefinesProxy(m_defines_proxy.get()); + m_set_define_proxy->SetDefinesProxy(m_defines_proxy.get()); m_stream = m_skip_until_first_non_empty_proxy.get(); } std::unique_ptr m_base_stream; std::unique_ptr m_templating_proxy; + std::unique_ptr m_set_define_proxy; std::unique_ptr m_defines_proxy; std::unique_ptr m_directive_escape_proxy; std::unique_ptr m_skip_until_first_non_empty_proxy; diff --git a/src/RawTemplater/Templating/TemplatingStreamProxy.cpp b/src/RawTemplater/Templating/TemplatingStreamProxy.cpp index b3725f08..b6c527a3 100644 --- a/src/RawTemplater/Templating/TemplatingStreamProxy.cpp +++ b/src/RawTemplater/Templating/TemplatingStreamProxy.cpp @@ -140,7 +140,7 @@ bool TemplatingStreamProxy::MatchFilenameDirective(const ParserLine& line, const return true; } -bool TemplatingStreamProxy::MatchDirectives(const ParserLine& line) +bool TemplatingStreamProxy::MatchDirectives(const ParserLine& line) const { unsigned directiveStartPos, directiveEndPos; diff --git a/src/RawTemplater/Templating/TemplatingStreamProxy.h b/src/RawTemplater/Templating/TemplatingStreamProxy.h index d6170c7d..64720e89 100644 --- a/src/RawTemplater/Templating/TemplatingStreamProxy.h +++ b/src/RawTemplater/Templating/TemplatingStreamProxy.h @@ -45,7 +45,7 @@ namespace templating _NODISCARD bool MatchSwitchDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition) const; _NODISCARD bool MatchOptionsDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition) const; _NODISCARD bool MatchFilenameDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition) const; - bool MatchDirectives(const ParserLine& line); + _NODISCARD bool MatchDirectives(const ParserLine& line) const; IParserLineStream* const m_stream; ITemplaterControl* const m_templater_control;