Add set define proxy to set a define based on an expression

This commit is contained in:
Jan 2022-09-06 21:45:55 +02:00
parent a36d1c430a
commit 03dd0f06b2
5 changed files with 138 additions and 3 deletions

View File

@ -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<char>::length(SET_DIRECTIVE)
|| !MatchString(line, currentPosition, SET_DIRECTIVE, std::char_traits<char>::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();
}

View File

@ -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;
};
}

View File

@ -8,6 +8,7 @@
#include "Utils/ClassUtils.h" #include "Utils/ClassUtils.h"
#include "DirectiveEscapeStreamProxy.h" #include "DirectiveEscapeStreamProxy.h"
#include "SetDefineStreamProxy.h"
#include "TemplatingStreamProxy.h" #include "TemplatingStreamProxy.h"
#include "Parsing/ParsingException.h" #include "Parsing/ParsingException.h"
#include "Parsing/Impl/DefinesStreamProxy.h" #include "Parsing/Impl/DefinesStreamProxy.h"
@ -32,16 +33,19 @@ namespace templating
m_base_stream = std::make_unique<ParserSingleInputStream>(stream, fileName); m_base_stream = std::make_unique<ParserSingleInputStream>(stream, fileName);
m_templating_proxy = std::make_unique<TemplatingStreamProxy>(m_base_stream.get(), templaterControl); m_templating_proxy = std::make_unique<TemplatingStreamProxy>(m_base_stream.get(), templaterControl);
m_defines_proxy = std::make_unique<DefinesStreamProxy>(m_templating_proxy.get(), true); m_set_define_proxy = std::make_unique<SetDefineStreamProxy>(m_templating_proxy.get());
m_defines_proxy = std::make_unique<DefinesStreamProxy>(m_set_define_proxy.get(), true);
m_directive_escape_proxy = std::make_unique<DirectiveEscapeStreamProxy>(m_defines_proxy.get()); m_directive_escape_proxy = std::make_unique<DirectiveEscapeStreamProxy>(m_defines_proxy.get());
m_skip_until_first_non_empty_proxy = std::make_unique<SkipUntilFirstNonEmptyProxy>(m_directive_escape_proxy.get()); m_skip_until_first_non_empty_proxy = std::make_unique<SkipUntilFirstNonEmptyProxy>(m_directive_escape_proxy.get());
m_templating_proxy->SetDefinesProxy(m_defines_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(); m_stream = m_skip_until_first_non_empty_proxy.get();
} }
std::unique_ptr<IParserLineStream> m_base_stream; std::unique_ptr<IParserLineStream> m_base_stream;
std::unique_ptr<TemplatingStreamProxy> m_templating_proxy; std::unique_ptr<TemplatingStreamProxy> m_templating_proxy;
std::unique_ptr<SetDefineStreamProxy> m_set_define_proxy;
std::unique_ptr<DefinesStreamProxy> m_defines_proxy; std::unique_ptr<DefinesStreamProxy> m_defines_proxy;
std::unique_ptr<DirectiveEscapeStreamProxy> m_directive_escape_proxy; std::unique_ptr<DirectiveEscapeStreamProxy> m_directive_escape_proxy;
std::unique_ptr<SkipUntilFirstNonEmptyProxy> m_skip_until_first_non_empty_proxy; std::unique_ptr<SkipUntilFirstNonEmptyProxy> m_skip_until_first_non_empty_proxy;

View File

@ -140,7 +140,7 @@ bool TemplatingStreamProxy::MatchFilenameDirective(const ParserLine& line, const
return true; return true;
} }
bool TemplatingStreamProxy::MatchDirectives(const ParserLine& line) bool TemplatingStreamProxy::MatchDirectives(const ParserLine& line) const
{ {
unsigned directiveStartPos, directiveEndPos; unsigned directiveStartPos, directiveEndPos;

View File

@ -45,7 +45,7 @@ namespace templating
_NODISCARD bool MatchSwitchDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition) const; _NODISCARD bool MatchSwitchDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition) const;
_NODISCARD bool MatchOptionsDirective(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; _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; IParserLineStream* const m_stream;
ITemplaterControl* const m_templater_control; ITemplaterControl* const m_templater_control;