mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-20 00:02:55 +00:00
Add raw templater
This commit is contained in:
parent
4ef38264c8
commit
1464329245
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
local/
|
local/
|
||||||
build/
|
build/
|
||||||
|
.vscode
|
||||||
user*.*
|
user*.*
|
@ -100,6 +100,7 @@ include "src/Common.lua"
|
|||||||
include "src/Crypto.lua"
|
include "src/Crypto.lua"
|
||||||
include "src/Linker.lua"
|
include "src/Linker.lua"
|
||||||
include "src/Parser.lua"
|
include "src/Parser.lua"
|
||||||
|
include "src/RawTemplater.lua"
|
||||||
include "src/Unlinker.lua"
|
include "src/Unlinker.lua"
|
||||||
include "src/Utils.lua"
|
include "src/Utils.lua"
|
||||||
include "src/ZoneCode.lua"
|
include "src/ZoneCode.lua"
|
||||||
@ -130,11 +131,16 @@ group "Components"
|
|||||||
ObjWriting:project()
|
ObjWriting:project()
|
||||||
group ""
|
group ""
|
||||||
|
|
||||||
|
-- Tools group: All projects that compile into the final tools
|
||||||
|
group "BuildTools"
|
||||||
|
RawTemplater:project()
|
||||||
|
ZoneCodeGenerator:project()
|
||||||
|
group ""
|
||||||
|
|
||||||
-- Tools group: All projects that compile into the final tools
|
-- Tools group: All projects that compile into the final tools
|
||||||
group "Tools"
|
group "Tools"
|
||||||
Linker:project()
|
Linker:project()
|
||||||
Unlinker:project()
|
Unlinker:project()
|
||||||
ZoneCodeGenerator:project()
|
|
||||||
group ""
|
group ""
|
||||||
|
|
||||||
group "Raw"
|
group "Raw"
|
||||||
|
0
raw/iw4/techniques/technique_test.technique
Normal file
0
raw/iw4/techniques/technique_test.technique
Normal file
14
raw/iw4/techniques/technique_test.technique.template
Normal file
14
raw/iw4/techniques/technique_test.technique.template
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma options TEST(asdf, bla)
|
||||||
|
#pragma switch TEST_SWITCH
|
||||||
|
|
||||||
|
#ifdef TEST_SWITCH
|
||||||
|
#define SVAL "1"
|
||||||
|
#else
|
||||||
|
#define SVAL "0"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma filename "lemao_" + TEST + SVAL + ".txt"
|
||||||
|
HAHA TEST
|
||||||
|
#ifdef TEST_SWITCH
|
||||||
|
kekw
|
||||||
|
#endif
|
@ -8,7 +8,7 @@ DefinesExpressionMatchers::DefinesExpressionMatchers()
|
|||||||
}
|
}
|
||||||
|
|
||||||
DefinesExpressionMatchers::DefinesExpressionMatchers(const DefinesDirectiveParsingState* state)
|
DefinesExpressionMatchers::DefinesExpressionMatchers(const DefinesDirectiveParsingState* state)
|
||||||
: SimpleExpressionMatchers(false, false, true, true, false),
|
: SimpleExpressionMatchers(true, false, true, true, false),
|
||||||
m_state(state)
|
m_state(state)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -281,13 +281,13 @@ bool DefinesStreamProxy::MatchUndefDirective(const ParserLine& line, const unsig
|
|||||||
std::unique_ptr<ISimpleExpression> DefinesStreamProxy::ParseExpression(const std::string& expressionString) const
|
std::unique_ptr<ISimpleExpression> DefinesStreamProxy::ParseExpression(const std::string& expressionString) const
|
||||||
{
|
{
|
||||||
std::istringstream ss(expressionString);
|
std::istringstream ss(expressionString);
|
||||||
ParserSingleInputStream inputStream(ss, "#if expression");
|
ParserSingleInputStream inputStream(ss, "defines directive expression");
|
||||||
|
|
||||||
SimpleLexer::Config lexerConfig;
|
SimpleLexer::Config lexerConfig;
|
||||||
lexerConfig.m_emit_new_line_tokens = false;
|
lexerConfig.m_emit_new_line_tokens = false;
|
||||||
lexerConfig.m_read_integer_numbers = true;
|
lexerConfig.m_read_integer_numbers = true;
|
||||||
lexerConfig.m_read_floating_point_numbers = true;
|
lexerConfig.m_read_floating_point_numbers = true;
|
||||||
lexerConfig.m_read_strings = false;
|
lexerConfig.m_read_strings = true;
|
||||||
SimpleExpressionMatchers().ApplyTokensToLexerConfig(lexerConfig);
|
SimpleExpressionMatchers().ApplyTokensToLexerConfig(lexerConfig);
|
||||||
|
|
||||||
SimpleLexer lexer(&inputStream, std::move(lexerConfig));
|
SimpleLexer lexer(&inputStream, std::move(lexerConfig));
|
||||||
|
@ -77,7 +77,6 @@ private:
|
|||||||
|
|
||||||
static void ExtractParametersFromDefineUsage(const ParserLine& line, unsigned parameterStart, unsigned& parameterEnd, std::vector<std::string>& parameterValues);
|
static void ExtractParametersFromDefineUsage(const ParserLine& line, unsigned parameterStart, unsigned& parameterEnd, std::vector<std::string>& parameterValues);
|
||||||
bool FindDefineForWord(const ParserLine& line, unsigned wordStart, unsigned wordEnd, Define*& value);
|
bool FindDefineForWord(const ParserLine& line, unsigned wordStart, unsigned wordEnd, Define*& value);
|
||||||
void ExpandDefines(ParserLine& line);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DefinesStreamProxy(IParserLineStream* stream);
|
explicit DefinesStreamProxy(IParserLineStream* stream);
|
||||||
@ -85,6 +84,8 @@ public:
|
|||||||
void AddDefine(Define define);
|
void AddDefine(Define define);
|
||||||
void Undefine(const std::string& name);
|
void Undefine(const std::string& name);
|
||||||
|
|
||||||
|
void ExpandDefines(ParserLine& line);
|
||||||
|
|
||||||
_NODISCARD std::unique_ptr<ISimpleExpression> ParseExpression(const std::string& expressionString) const;
|
_NODISCARD std::unique_ptr<ISimpleExpression> ParseExpression(const std::string& expressionString) const;
|
||||||
|
|
||||||
ParserLine NextLine() override;
|
ParserLine NextLine() override;
|
||||||
|
@ -61,5 +61,5 @@ bool ParserSingleInputStream::IsOpen() const
|
|||||||
|
|
||||||
bool ParserSingleInputStream::Eof() const
|
bool ParserSingleInputStream::Eof() const
|
||||||
{
|
{
|
||||||
return !m_stream.eof();
|
return m_stream.eof();
|
||||||
}
|
}
|
||||||
|
50
src/RawTemplater.lua
Normal file
50
src/RawTemplater.lua
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
RawTemplater = {}
|
||||||
|
|
||||||
|
function RawTemplater:include(includes)
|
||||||
|
if includes:handle(self:name()) then
|
||||||
|
includedirs {
|
||||||
|
path.join(ProjectFolder(), "RawTemplater")
|
||||||
|
}
|
||||||
|
Utils:include(includes)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function RawTemplater:link(links)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function RawTemplater:use()
|
||||||
|
dependson(self:name())
|
||||||
|
end
|
||||||
|
|
||||||
|
function RawTemplater:name()
|
||||||
|
return "RawTemplater"
|
||||||
|
end
|
||||||
|
|
||||||
|
function RawTemplater:project()
|
||||||
|
local folder = ProjectFolder()
|
||||||
|
local includes = Includes:create()
|
||||||
|
local links = Links:create()
|
||||||
|
|
||||||
|
project(self:name())
|
||||||
|
targetdir(TargetDirectoryBin)
|
||||||
|
location "%{wks.location}/src/%{prj.name}"
|
||||||
|
kind "ConsoleApp"
|
||||||
|
language "C++"
|
||||||
|
|
||||||
|
files {
|
||||||
|
path.join(folder, "RawTemplater/**.h"),
|
||||||
|
path.join(folder, "RawTemplater/**.cpp")
|
||||||
|
}
|
||||||
|
vpaths {
|
||||||
|
["*"] = {
|
||||||
|
path.join(folder, "RawTemplater"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self:include(includes)
|
||||||
|
Parser:include(includes)
|
||||||
|
|
||||||
|
links:linkto(Parser)
|
||||||
|
links:linkall()
|
||||||
|
end
|
68
src/RawTemplater/RawTemplater.cpp
Normal file
68
src/RawTemplater/RawTemplater.cpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#include "RawTemplater.h"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
#include "RawTemplaterArguments.h"
|
||||||
|
#include "Templating/Templater.h"
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
class RawTemplater::Impl
|
||||||
|
{
|
||||||
|
RawTemplaterArguments m_args;
|
||||||
|
|
||||||
|
_NODISCARD bool GenerateCode(const std::string& filename) const
|
||||||
|
{
|
||||||
|
std::ifstream file(filename);
|
||||||
|
if (!file.is_open())
|
||||||
|
{
|
||||||
|
std::cerr << "Failed to open file \"" << filename << "\"\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
templating::Templater templater(file, filename);
|
||||||
|
if (!m_args.m_output_directory.empty())
|
||||||
|
return templater.TemplateToDirectory(m_args.m_output_directory);
|
||||||
|
|
||||||
|
const fs::path filePath(filename);
|
||||||
|
const auto parentPath = filePath.parent_path();
|
||||||
|
|
||||||
|
return templater.TemplateToDirectory(parentPath.string());
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Impl()
|
||||||
|
= default;
|
||||||
|
|
||||||
|
int Run(const int argc, const char** argv)
|
||||||
|
{
|
||||||
|
if (!m_args.Parse(argc, argv))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
for(const auto& inputFile : m_args.m_input_files)
|
||||||
|
{
|
||||||
|
if (!GenerateCode(inputFile))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
RawTemplater::RawTemplater()
|
||||||
|
{
|
||||||
|
m_impl = new Impl();
|
||||||
|
}
|
||||||
|
|
||||||
|
RawTemplater::~RawTemplater()
|
||||||
|
{
|
||||||
|
delete m_impl;
|
||||||
|
m_impl = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RawTemplater::Run(const int argc, const char** argv) const
|
||||||
|
{
|
||||||
|
return m_impl->Run(argc, argv);
|
||||||
|
}
|
17
src/RawTemplater/RawTemplater.h
Normal file
17
src/RawTemplater/RawTemplater.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class RawTemplater
|
||||||
|
{
|
||||||
|
class Impl;
|
||||||
|
Impl* m_impl;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RawTemplater();
|
||||||
|
~RawTemplater();
|
||||||
|
RawTemplater(const RawTemplater& other) = delete;
|
||||||
|
RawTemplater(RawTemplater&& other) noexcept = default;
|
||||||
|
RawTemplater& operator=(const RawTemplater& other) = delete;
|
||||||
|
RawTemplater& operator=(RawTemplater&& other) noexcept = default;
|
||||||
|
|
||||||
|
int Run(int argc, const char** argv) const;
|
||||||
|
};
|
105
src/RawTemplater/RawTemplaterArguments.cpp
Normal file
105
src/RawTemplater/RawTemplaterArguments.cpp
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#include "RawTemplaterArguments.h"
|
||||||
|
|
||||||
|
#include "Utils/Arguments/CommandLineOption.h"
|
||||||
|
#include "Utils/Arguments/UsageInformation.h"
|
||||||
|
|
||||||
|
const CommandLineOption* const OPTION_HELP = CommandLineOption::Builder::Create()
|
||||||
|
.WithShortName("?")
|
||||||
|
.WithLongName("help")
|
||||||
|
.WithDescription("Displays usage information.")
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
const CommandLineOption* const OPTION_VERBOSE = CommandLineOption::Builder::Create()
|
||||||
|
.WithShortName("v")
|
||||||
|
.WithLongName("verbose")
|
||||||
|
.WithDescription("Outputs a lot more and more detailed messages.")
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
const CommandLineOption* const OPTION_OUTPUT_FOLDER = CommandLineOption::Builder::Create()
|
||||||
|
.WithShortName("o")
|
||||||
|
.WithLongName("output")
|
||||||
|
.WithDescription("Specify the folder to save the generated files. Defaults to the current directory.")
|
||||||
|
.WithParameter("outputPath")
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
const CommandLineOption* const OPTION_DEFINE = CommandLineOption::Builder::Create()
|
||||||
|
.WithShortName("d")
|
||||||
|
.WithLongName("define")
|
||||||
|
.WithDescription("Adds a define for the templating process. Can be of format define or define=value.")
|
||||||
|
.WithParameter("defineValue")
|
||||||
|
.Reusable()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
const CommandLineOption* const COMMAND_LINE_OPTIONS[]
|
||||||
|
{
|
||||||
|
OPTION_HELP,
|
||||||
|
OPTION_VERBOSE,
|
||||||
|
OPTION_OUTPUT_FOLDER,
|
||||||
|
OPTION_DEFINE
|
||||||
|
};
|
||||||
|
|
||||||
|
RawTemplaterArguments::RawTemplaterArguments()
|
||||||
|
: m_argument_parser(COMMAND_LINE_OPTIONS, std::extent_v<decltype(COMMAND_LINE_OPTIONS)>),
|
||||||
|
m_verbose(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void RawTemplaterArguments::PrintUsage()
|
||||||
|
{
|
||||||
|
UsageInformation usage("RawTemplater.exe");
|
||||||
|
|
||||||
|
for (const auto* commandLineOption : COMMAND_LINE_OPTIONS)
|
||||||
|
{
|
||||||
|
usage.AddCommandLineOption(commandLineOption);
|
||||||
|
}
|
||||||
|
|
||||||
|
usage.Print();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RawTemplaterArguments::Parse(const int argc, const char** argv)
|
||||||
|
{
|
||||||
|
if (!m_argument_parser.ParseArguments(argc - 1, &argv[1]))
|
||||||
|
{
|
||||||
|
PrintUsage();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the user requested help
|
||||||
|
if (m_argument_parser.IsOptionSpecified(OPTION_HELP))
|
||||||
|
{
|
||||||
|
PrintUsage();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_input_files = m_argument_parser.GetArguments();
|
||||||
|
if (m_input_files.empty())
|
||||||
|
{
|
||||||
|
PrintUsage();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -v; --verbose
|
||||||
|
m_verbose = m_argument_parser.IsOptionSpecified(OPTION_VERBOSE);
|
||||||
|
|
||||||
|
// -o; --output
|
||||||
|
if (m_argument_parser.IsOptionSpecified(OPTION_OUTPUT_FOLDER))
|
||||||
|
m_output_directory = m_argument_parser.GetValueForOption(OPTION_OUTPUT_FOLDER);
|
||||||
|
else
|
||||||
|
m_output_directory = ".";
|
||||||
|
|
||||||
|
// -d; --define
|
||||||
|
if (m_argument_parser.IsOptionSpecified(OPTION_DEFINE))
|
||||||
|
{
|
||||||
|
for (const auto& arg : m_argument_parser.GetParametersForOption(OPTION_DEFINE))
|
||||||
|
{
|
||||||
|
const auto separator = arg.find('=');
|
||||||
|
|
||||||
|
if (separator != std::string::npos)
|
||||||
|
m_defines.emplace_back(std::make_pair(arg.substr(0, separator), arg.substr(separator + 1)));
|
||||||
|
else
|
||||||
|
m_defines.emplace_back(std::make_pair(arg, std::string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
29
src/RawTemplater/RawTemplaterArguments.h
Normal file
29
src/RawTemplater/RawTemplaterArguments.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Utils/Arguments/ArgumentParser.h"
|
||||||
|
|
||||||
|
class RawTemplaterArguments
|
||||||
|
{
|
||||||
|
ArgumentParser m_argument_parser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Prints a command line usage help text for the RawTemplater tool to stdout.
|
||||||
|
*/
|
||||||
|
static void PrintUsage();
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool m_verbose;
|
||||||
|
|
||||||
|
std::vector<std::string> m_input_files;
|
||||||
|
std::string m_output_directory;
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string, std::string>> m_defines;
|
||||||
|
|
||||||
|
RawTemplaterArguments();
|
||||||
|
|
||||||
|
bool Parse(int argc, const char** argv);
|
||||||
|
};
|
38
src/RawTemplater/Templating/DirectiveEscapeStreamProxy.cpp
Normal file
38
src/RawTemplater/Templating/DirectiveEscapeStreamProxy.cpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#include "DirectiveEscapeStreamProxy.h"
|
||||||
|
|
||||||
|
using namespace templating;
|
||||||
|
|
||||||
|
DirectiveEscapeStreamProxy::DirectiveEscapeStreamProxy(IParserLineStream* stream)
|
||||||
|
: m_stream(stream)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ParserLine DirectiveEscapeStreamProxy::NextLine()
|
||||||
|
{
|
||||||
|
auto line = m_stream->NextLine();
|
||||||
|
|
||||||
|
if (line.m_line.size() >= 2 && line.m_line[0] == '#' && line.m_line[1] == '#')
|
||||||
|
line.m_line = line.m_line.substr(1);
|
||||||
|
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DirectiveEscapeStreamProxy::IncludeFile(const std::string& filename)
|
||||||
|
{
|
||||||
|
return m_stream->IncludeFile(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirectiveEscapeStreamProxy::PopCurrentFile()
|
||||||
|
{
|
||||||
|
m_stream->PopCurrentFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DirectiveEscapeStreamProxy::IsOpen() const
|
||||||
|
{
|
||||||
|
return m_stream->IsOpen();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DirectiveEscapeStreamProxy::Eof() const
|
||||||
|
{
|
||||||
|
return m_stream->Eof();
|
||||||
|
}
|
20
src/RawTemplater/Templating/DirectiveEscapeStreamProxy.h
Normal file
20
src/RawTemplater/Templating/DirectiveEscapeStreamProxy.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Parsing/Impl/AbstractDirectiveStreamProxy.h"
|
||||||
|
|
||||||
|
namespace templating
|
||||||
|
{
|
||||||
|
class DirectiveEscapeStreamProxy final : public AbstractDirectiveStreamProxy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit DirectiveEscapeStreamProxy(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;
|
||||||
|
|
||||||
|
private:
|
||||||
|
IParserLineStream* const m_stream;
|
||||||
|
};
|
||||||
|
}
|
354
src/RawTemplater/Templating/Templater.cpp
Normal file
354
src/RawTemplater/Templating/Templater.cpp
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
#include "Templater.h"
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "Utils/ClassUtils.h"
|
||||||
|
#include "DirectiveEscapeStreamProxy.h"
|
||||||
|
#include "TemplatingStreamProxy.h"
|
||||||
|
#include "Parsing/ParsingException.h"
|
||||||
|
#include "Parsing/Impl/DefinesStreamProxy.h"
|
||||||
|
#include "Parsing/Impl/ParserSingleInputStream.h"
|
||||||
|
|
||||||
|
using namespace templating;
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
namespace templating
|
||||||
|
{
|
||||||
|
class TemplatingPass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TemplatingPass()
|
||||||
|
: m_stream(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TemplatingPass(std::istream& stream, const std::string& fileName, ITemplaterControl* templaterControl)
|
||||||
|
{
|
||||||
|
m_base_stream = std::make_unique<ParserSingleInputStream>(stream, fileName);
|
||||||
|
|
||||||
|
m_templating_proxy = std::make_unique<TemplatingStreamProxy>(m_base_stream.get(), templaterControl);
|
||||||
|
m_defines_proxy = std::make_unique<DefinesStreamProxy>(m_templating_proxy.get());
|
||||||
|
m_directive_escape_proxy = std::make_unique<DirectiveEscapeStreamProxy>(m_defines_proxy.get());
|
||||||
|
|
||||||
|
m_templating_proxy->SetDefinesProxy(m_defines_proxy.get());
|
||||||
|
m_stream = m_directive_escape_proxy.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<IParserLineStream> m_base_stream;
|
||||||
|
std::unique_ptr<TemplatingStreamProxy> m_templating_proxy;
|
||||||
|
std::unique_ptr<DefinesStreamProxy> m_defines_proxy;
|
||||||
|
std::unique_ptr<DirectiveEscapeStreamProxy> m_directive_escape_proxy;
|
||||||
|
IParserLineStream* m_stream;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class TemplatingVariationType
|
||||||
|
{
|
||||||
|
OPTIONS,
|
||||||
|
SWITCH
|
||||||
|
};
|
||||||
|
|
||||||
|
class ITemplatingVariation
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
ITemplatingVariation() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~ITemplatingVariation() = default;
|
||||||
|
ITemplatingVariation(const ITemplatingVariation& other) = default;
|
||||||
|
ITemplatingVariation(ITemplatingVariation&& other) noexcept = default;
|
||||||
|
ITemplatingVariation& operator=(const ITemplatingVariation& other) = default;
|
||||||
|
ITemplatingVariation& operator=(ITemplatingVariation&& other) noexcept = default;
|
||||||
|
|
||||||
|
virtual const std::string& GetName() = 0;
|
||||||
|
virtual void Advance() = 0;
|
||||||
|
virtual void Apply(DefinesStreamProxy* definesProxy) = 0;
|
||||||
|
_NODISCARD virtual bool IsFinished() const = 0;
|
||||||
|
_NODISCARD virtual TemplatingVariationType GetVariationType() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SwitchVariation final : public ITemplatingVariation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit SwitchVariation(std::string name)
|
||||||
|
: m_name(std::move(name)),
|
||||||
|
m_should_define(true),
|
||||||
|
m_finished(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& GetName() override
|
||||||
|
{
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Advance() override
|
||||||
|
{
|
||||||
|
if (!m_should_define)
|
||||||
|
m_finished = true;
|
||||||
|
else
|
||||||
|
m_should_define = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Apply(DefinesStreamProxy* definesProxy) override
|
||||||
|
{
|
||||||
|
if (m_should_define)
|
||||||
|
definesProxy->AddDefine(DefinesStreamProxy::Define(m_name, "1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
_NODISCARD bool IsFinished() const override
|
||||||
|
{
|
||||||
|
return m_finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
_NODISCARD TemplatingVariationType GetVariationType() const override
|
||||||
|
{
|
||||||
|
return TemplatingVariationType::SWITCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string m_name;
|
||||||
|
bool m_should_define;
|
||||||
|
bool m_finished;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OptionsVariation final : public ITemplatingVariation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OptionsVariation(std::string name, std::vector<std::string> values)
|
||||||
|
: m_name(std::move(name)),
|
||||||
|
m_values(std::move(values)),
|
||||||
|
m_value_offset(0u)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& GetName() override
|
||||||
|
{
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Advance() override
|
||||||
|
{
|
||||||
|
m_value_offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Apply(DefinesStreamProxy* definesProxy) override
|
||||||
|
{
|
||||||
|
if (m_value_offset < m_values.size())
|
||||||
|
definesProxy->AddDefine(DefinesStreamProxy::Define(m_name, m_values[m_value_offset]));
|
||||||
|
}
|
||||||
|
|
||||||
|
_NODISCARD bool IsFinished() const override
|
||||||
|
{
|
||||||
|
return m_value_offset >= m_values.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
_NODISCARD TemplatingVariationType GetVariationType() const override
|
||||||
|
{
|
||||||
|
return TemplatingVariationType::OPTIONS;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string m_name;
|
||||||
|
std::vector<std::string> m_values;
|
||||||
|
size_t m_value_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TemplaterControlImpl final : ITemplaterControl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TemplaterControlImpl(std::istream& stream, std::string filename, const std::string& outputDirectory)
|
||||||
|
: m_stream(stream),
|
||||||
|
m_filename(std::move(filename)),
|
||||||
|
m_output_directory(outputDirectory),
|
||||||
|
m_first_line(true),
|
||||||
|
m_write_output_to_file(false)
|
||||||
|
{
|
||||||
|
fs::path filenamePath(m_filename);
|
||||||
|
m_default_output_file = (m_output_directory / filenamePath.replace_extension()).string();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RunNextPass()
|
||||||
|
{
|
||||||
|
m_stream.clear();
|
||||||
|
m_stream.seekg(0, std::ios::beg);
|
||||||
|
|
||||||
|
m_output_file = m_default_output_file;
|
||||||
|
m_current_pass = TemplatingPass(m_stream, m_filename, this);
|
||||||
|
|
||||||
|
for (const auto& activeVariation : m_active_variations)
|
||||||
|
activeVariation->Apply(m_current_pass.m_defines_proxy.get());
|
||||||
|
|
||||||
|
while (!m_current_pass.m_stream->Eof())
|
||||||
|
{
|
||||||
|
auto nextLine = m_current_pass.m_stream->NextLine();
|
||||||
|
|
||||||
|
if (m_write_output_to_file)
|
||||||
|
{
|
||||||
|
if (m_first_line)
|
||||||
|
m_first_line = false;
|
||||||
|
else
|
||||||
|
m_output_stream << '\n';
|
||||||
|
|
||||||
|
m_output_stream << nextLine.m_line;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (m_first_line)
|
||||||
|
m_first_line = false;
|
||||||
|
else
|
||||||
|
m_output_cache << '\n';
|
||||||
|
|
||||||
|
m_output_cache << nextLine.m_line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_write_output_to_file)
|
||||||
|
{
|
||||||
|
m_output_stream = std::ofstream(m_output_file);
|
||||||
|
if (!m_output_stream.is_open())
|
||||||
|
{
|
||||||
|
std::cerr << "Failed to open output file \"" << m_output_file << "\"\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto cachedData = m_output_cache.str();
|
||||||
|
if (!cachedData.empty())
|
||||||
|
m_output_stream << cachedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_first_line = true;
|
||||||
|
m_write_output_to_file = false;
|
||||||
|
m_output_cache.clear();
|
||||||
|
m_output_cache.str(std::string());
|
||||||
|
m_output_stream.close();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvanceActiveVariations()
|
||||||
|
{
|
||||||
|
while (!m_active_variations.empty())
|
||||||
|
{
|
||||||
|
const auto& lastVariation = m_active_variations[m_active_variations.size() - 1];
|
||||||
|
lastVariation->Advance();
|
||||||
|
|
||||||
|
if (lastVariation->IsFinished())
|
||||||
|
{
|
||||||
|
m_active_variations_by_name.erase(lastVariation->GetName());
|
||||||
|
m_active_variations.pop_back();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_NODISCARD bool HasActiveVariations() const
|
||||||
|
{
|
||||||
|
return !m_active_variations.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool AddSwitch(std::string switchName) override
|
||||||
|
{
|
||||||
|
const auto existingVariation = m_active_variations_by_name.find(switchName);
|
||||||
|
if (existingVariation != m_active_variations_by_name.end())
|
||||||
|
return existingVariation->second->GetVariationType() == TemplatingVariationType::SWITCH;
|
||||||
|
|
||||||
|
auto switchVariation = std::make_unique<SwitchVariation>(std::move(switchName));
|
||||||
|
if (m_current_pass.m_defines_proxy)
|
||||||
|
switchVariation->Apply(m_current_pass.m_defines_proxy.get());
|
||||||
|
m_active_variations_by_name.emplace(switchVariation->m_name, switchVariation.get());
|
||||||
|
m_active_variations.emplace_back(std::move(switchVariation));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AddOptions(std::string optionsName, std::vector<std::string> optionValues) override
|
||||||
|
{
|
||||||
|
const auto existingVariation = m_active_variations_by_name.find(optionsName);
|
||||||
|
if (existingVariation != m_active_variations_by_name.end())
|
||||||
|
return existingVariation->second->GetVariationType() == TemplatingVariationType::SWITCH;
|
||||||
|
|
||||||
|
auto optionsVariation = std::make_unique<OptionsVariation>(std::move(optionsName), std::move(optionValues));
|
||||||
|
if (m_current_pass.m_defines_proxy)
|
||||||
|
optionsVariation->Apply(m_current_pass.m_defines_proxy.get());
|
||||||
|
m_active_variations_by_name.emplace(optionsVariation->m_name, optionsVariation.get());
|
||||||
|
m_active_variations.emplace_back(std::move(optionsVariation));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SetFileName(const std::string& fileName) override
|
||||||
|
{
|
||||||
|
if (m_write_output_to_file)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_output_file = fileName;
|
||||||
|
m_output_stream = std::ofstream(m_output_file);
|
||||||
|
if (!m_output_stream.is_open())
|
||||||
|
{
|
||||||
|
std::cerr << "Failed to open output file \"" << m_output_file << "\"\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_write_output_to_file = true;
|
||||||
|
const auto cachedData = m_output_cache.str();
|
||||||
|
if (!cachedData.empty())
|
||||||
|
m_output_stream << cachedData;
|
||||||
|
m_output_cache.clear();
|
||||||
|
m_output_cache.str(std::string());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::unique_ptr<ITemplatingVariation>> m_active_variations;
|
||||||
|
std::unordered_map<std::string, ITemplatingVariation*> m_active_variations_by_name;
|
||||||
|
TemplatingPass m_current_pass;
|
||||||
|
|
||||||
|
std::istream& m_stream;
|
||||||
|
std::string m_filename;
|
||||||
|
std::string m_output_file;
|
||||||
|
std::string m_default_output_file;
|
||||||
|
const fs::path m_output_directory;
|
||||||
|
|
||||||
|
bool m_first_line;
|
||||||
|
bool m_write_output_to_file;
|
||||||
|
std::ofstream m_output_stream;
|
||||||
|
std::ostringstream m_output_cache;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Templater::Templater(std::istream& stream, std::string fileName)
|
||||||
|
: m_stream(stream),
|
||||||
|
m_file_name(std::move(fileName))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Templater::TemplateToDirectory(const std::string& outputDirectory)
|
||||||
|
{
|
||||||
|
TemplaterControlImpl control(m_stream, m_file_name, outputDirectory);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!control.RunNextPass())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
control.AdvanceActiveVariations();
|
||||||
|
while (control.HasActiveVariations())
|
||||||
|
{
|
||||||
|
if (!control.RunNextPass())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
control.AdvanceActiveVariations();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ParsingException& e)
|
||||||
|
{
|
||||||
|
std::cerr << "Error: " << e.FullMessage() << std::endl;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
19
src/RawTemplater/Templating/Templater.h
Normal file
19
src/RawTemplater/Templating/Templater.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "Parsing/IParserLineStream.h"
|
||||||
|
|
||||||
|
namespace templating
|
||||||
|
{
|
||||||
|
class Templater
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Templater(std::istream& stream, std::string fileName);
|
||||||
|
|
||||||
|
bool TemplateToDirectory(const std::string& outputDirectory);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::istream& m_stream;
|
||||||
|
std::string m_file_name;
|
||||||
|
};
|
||||||
|
}
|
196
src/RawTemplater/Templating/TemplatingStreamProxy.cpp
Normal file
196
src/RawTemplater/Templating/TemplatingStreamProxy.cpp
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
#include "TemplatingStreamProxy.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "Parsing/ParsingException.h"
|
||||||
|
|
||||||
|
using namespace templating;
|
||||||
|
|
||||||
|
TemplatingStreamProxy::TemplatingStreamProxy(IParserLineStream* stream, ITemplaterControl* templaterControl)
|
||||||
|
: m_stream(stream),
|
||||||
|
m_templater_control(templaterControl),
|
||||||
|
m_defines_proxy(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void TemplatingStreamProxy::SetDefinesProxy(DefinesStreamProxy* definesProxy)
|
||||||
|
{
|
||||||
|
m_defines_proxy = definesProxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TemplatingStreamProxy::MatchSwitchDirective(const ParserLine& line, const unsigned directiveStartPosition, const unsigned directiveEndPosition) const
|
||||||
|
{
|
||||||
|
auto currentPosition = directiveStartPosition;
|
||||||
|
|
||||||
|
if (directiveEndPosition - directiveStartPosition != std::char_traits<char>::length(PRAGMA_DIRECTIVE)
|
||||||
|
|| !MatchString(line, currentPosition, PRAGMA_DIRECTIVE, std::char_traits<char>::length(PRAGMA_DIRECTIVE)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SkipWhitespace(line, currentPosition))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!MatchString(line, currentPosition, SWITCH_PRAGMA_COMMAND, std::char_traits<char>::length(SWITCH_PRAGMA_COMMAND)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!SkipWhitespace(line, currentPosition))
|
||||||
|
throw ParsingException(CreatePos(line, currentPosition), "Invalid switch directive.");
|
||||||
|
|
||||||
|
const auto nameStartPosition = currentPosition;
|
||||||
|
if (!ExtractIdentifier(line, currentPosition))
|
||||||
|
throw ParsingException(CreatePos(line, currentPosition), "Invalid switch directive.");
|
||||||
|
|
||||||
|
auto name = line.m_line.substr(nameStartPosition, currentPosition - nameStartPosition);
|
||||||
|
|
||||||
|
std::cout << "Switch: \"" << name << "\"\n";
|
||||||
|
m_templater_control->AddSwitch(std::move(name));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TemplatingStreamProxy::MatchOptionsDirective(const ParserLine& line, const unsigned directiveStartPosition, const unsigned directiveEndPosition) const
|
||||||
|
{
|
||||||
|
auto currentPosition = directiveStartPosition;
|
||||||
|
|
||||||
|
if (directiveEndPosition - directiveStartPosition != std::char_traits<char>::length(PRAGMA_DIRECTIVE)
|
||||||
|
|| !MatchString(line, currentPosition, PRAGMA_DIRECTIVE, std::char_traits<char>::length(PRAGMA_DIRECTIVE)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SkipWhitespace(line, currentPosition))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!MatchString(line, currentPosition, OPTIONS_PRAGMA_COMMAND, std::char_traits<char>::length(OPTIONS_PRAGMA_COMMAND)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!SkipWhitespace(line, currentPosition))
|
||||||
|
throw ParsingException(CreatePos(line, currentPosition), "Invalid options directive.");
|
||||||
|
|
||||||
|
const auto nameStartPosition = currentPosition;
|
||||||
|
if (!ExtractIdentifier(line, currentPosition))
|
||||||
|
throw ParsingException(CreatePos(line, currentPosition), "Invalid options directive.");
|
||||||
|
|
||||||
|
auto name = line.m_line.substr(nameStartPosition, currentPosition - nameStartPosition);
|
||||||
|
|
||||||
|
if (!MatchNextCharacter(line, currentPosition, '('))
|
||||||
|
throw ParsingException(CreatePos(line, currentPosition), "Invalid options directive.");
|
||||||
|
|
||||||
|
std::vector<std::string> options;
|
||||||
|
|
||||||
|
if (!SkipWhitespace(line, currentPosition))
|
||||||
|
throw ParsingException(CreatePos(line, currentPosition), "Invalid options directive.");
|
||||||
|
|
||||||
|
bool firstArg = true;
|
||||||
|
while (!MatchNextCharacter(line, currentPosition, ')'))
|
||||||
|
{
|
||||||
|
if (!firstArg && !MatchNextCharacter(line, currentPosition, ','))
|
||||||
|
throw ParsingException(CreatePos(line, currentPosition), "Invalid options directive.");
|
||||||
|
if (!SkipWhitespace(line, currentPosition))
|
||||||
|
throw ParsingException(CreatePos(line, currentPosition), "Invalid options directive.");
|
||||||
|
|
||||||
|
const auto optionStartPosition = currentPosition;
|
||||||
|
if (!ExtractIdentifier(line, currentPosition))
|
||||||
|
throw ParsingException(CreatePos(line, currentPosition), "Invalid options directive.");
|
||||||
|
|
||||||
|
std::ostringstream optionValueBuilder;
|
||||||
|
optionValueBuilder << '"' << line.m_line.substr(optionStartPosition, currentPosition - optionStartPosition) << '"';
|
||||||
|
options.emplace_back(optionValueBuilder.str());
|
||||||
|
|
||||||
|
firstArg = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Options: \"" << name << "\" with values:\n";
|
||||||
|
for (const auto& option : options)
|
||||||
|
std::cout << " Value: " << option << "\n";
|
||||||
|
|
||||||
|
m_templater_control->AddOptions(std::move(name), std::move(options));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TemplatingStreamProxy::MatchFilenameDirective(const ParserLine& line, const unsigned directiveStartPosition, const unsigned directiveEndPosition) const
|
||||||
|
{
|
||||||
|
auto currentPosition = directiveStartPosition;
|
||||||
|
|
||||||
|
if (directiveEndPosition - directiveStartPosition != std::char_traits<char>::length(PRAGMA_DIRECTIVE)
|
||||||
|
|| !MatchString(line, currentPosition, PRAGMA_DIRECTIVE, std::char_traits<char>::length(PRAGMA_DIRECTIVE)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SkipWhitespace(line, currentPosition))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!MatchString(line, currentPosition, FILENAME_PRAGMA_COMMAND, std::char_traits<char>::length(FILENAME_PRAGMA_COMMAND)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!SkipWhitespace(line, currentPosition))
|
||||||
|
throw ParsingException(CreatePos(line, currentPosition), "Invalid options directive.");
|
||||||
|
|
||||||
|
const auto expressionString = line.m_line.substr(currentPosition, line.m_line.size() - currentPosition);
|
||||||
|
if (expressionString.empty())
|
||||||
|
throw ParsingException(CreatePos(line, currentPosition), "Cannot pragma filename without an expression.");
|
||||||
|
|
||||||
|
ParserLine expressionStringAsLine(line.m_filename, line.m_line_number, expressionString);
|
||||||
|
m_defines_proxy->ExpandDefines(expressionStringAsLine);
|
||||||
|
|
||||||
|
const auto expression = m_defines_proxy->ParseExpression(expressionStringAsLine.m_line);
|
||||||
|
if (!expression)
|
||||||
|
throw ParsingException(CreatePos(line, currentPosition), "Failed to parse pragma filename expression");
|
||||||
|
|
||||||
|
if (!expression->IsStatic())
|
||||||
|
throw ParsingException(CreatePos(line, currentPosition), "pragma filename expression must be static");
|
||||||
|
|
||||||
|
const auto value = expression->EvaluateStatic();
|
||||||
|
|
||||||
|
if (value.m_type != SimpleExpressionValue::Type::STRING)
|
||||||
|
throw ParsingException(CreatePos(line, currentPosition), "pragma filename expression must evaluate to string");
|
||||||
|
|
||||||
|
std::cout << "Filename: \"" << *value.m_string_value << "\"\n";
|
||||||
|
m_templater_control->SetFileName(*value.m_string_value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TemplatingStreamProxy::MatchDirectives(const ParserLine& line)
|
||||||
|
{
|
||||||
|
unsigned directiveStartPos, directiveEndPos;
|
||||||
|
|
||||||
|
if (!FindDirective(line, directiveStartPos, directiveEndPos))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
directiveStartPos++;
|
||||||
|
|
||||||
|
return MatchSwitchDirective(line, directiveStartPos, directiveEndPos)
|
||||||
|
|| MatchOptionsDirective(line, directiveStartPos, directiveEndPos)
|
||||||
|
|| MatchFilenameDirective(line, directiveStartPos, directiveEndPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
ParserLine TemplatingStreamProxy::NextLine()
|
||||||
|
{
|
||||||
|
auto line = m_stream->NextLine();
|
||||||
|
|
||||||
|
while (MatchDirectives(line))
|
||||||
|
line = m_stream->NextLine();
|
||||||
|
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TemplatingStreamProxy::IncludeFile(const std::string& filename)
|
||||||
|
{
|
||||||
|
return m_stream->IncludeFile(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TemplatingStreamProxy::PopCurrentFile()
|
||||||
|
{
|
||||||
|
m_stream->PopCurrentFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TemplatingStreamProxy::IsOpen() const
|
||||||
|
{
|
||||||
|
return m_stream->IsOpen();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TemplatingStreamProxy::Eof() const
|
||||||
|
{
|
||||||
|
return m_stream->Eof();
|
||||||
|
}
|
54
src/RawTemplater/Templating/TemplatingStreamProxy.h
Normal file
54
src/RawTemplater/Templating/TemplatingStreamProxy.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Utils/ClassUtils.h"
|
||||||
|
#include "Parsing/Impl/AbstractDirectiveStreamProxy.h"
|
||||||
|
#include "Parsing/Impl/DefinesStreamProxy.h"
|
||||||
|
|
||||||
|
namespace templating
|
||||||
|
{
|
||||||
|
class ITemplaterControl
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
ITemplaterControl() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~ITemplaterControl() = default;
|
||||||
|
ITemplaterControl(const ITemplaterControl& other) = default;
|
||||||
|
ITemplaterControl(ITemplaterControl&& other) noexcept = default;
|
||||||
|
ITemplaterControl& operator=(const ITemplaterControl& other) = default;
|
||||||
|
ITemplaterControl& operator=(ITemplaterControl&& other) noexcept = default;
|
||||||
|
|
||||||
|
virtual bool AddSwitch(std::string switchName) = 0;
|
||||||
|
virtual bool AddOptions(std::string optionsName, std::vector<std::string> optionValues) = 0;
|
||||||
|
virtual bool SetFileName(const std::string& fileName) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TemplatingStreamProxy final : public AbstractDirectiveStreamProxy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TemplatingStreamProxy(IParserLineStream* stream, ITemplaterControl* templaterControl);
|
||||||
|
|
||||||
|
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* PRAGMA_DIRECTIVE = "pragma";
|
||||||
|
static constexpr const char* SWITCH_PRAGMA_COMMAND = "switch";
|
||||||
|
static constexpr const char* OPTIONS_PRAGMA_COMMAND = "options";
|
||||||
|
static constexpr const char* FILENAME_PRAGMA_COMMAND = "filename";
|
||||||
|
|
||||||
|
_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);
|
||||||
|
|
||||||
|
IParserLineStream* const m_stream;
|
||||||
|
ITemplaterControl* const m_templater_control;
|
||||||
|
DefinesStreamProxy* m_defines_proxy;
|
||||||
|
};
|
||||||
|
}
|
7
src/RawTemplater/main.cpp
Normal file
7
src/RawTemplater/main.cpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include "RawTemplater.h"
|
||||||
|
|
||||||
|
int main(const int argc, const char** argv)
|
||||||
|
{
|
||||||
|
const RawTemplater rawTemplater;
|
||||||
|
return rawTemplater.Run(argc, argv);
|
||||||
|
}
|
@ -39,7 +39,7 @@ function Raw:project()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
filter "files:**"
|
filter "files:not **/*.template"
|
||||||
buildmessage 'Copying rawfile %{file.relpath}'
|
buildmessage 'Copying rawfile %{file.relpath}'
|
||||||
buildcommands {
|
buildcommands {
|
||||||
-- Relpath contains two .. so build/raw is getting reverted in the target path
|
-- Relpath contains two .. so build/raw is getting reverted in the target path
|
||||||
@ -50,4 +50,14 @@ function Raw:project()
|
|||||||
"%{cfg.targetdir}/build/raw/%{file.relpath}"
|
"%{cfg.targetdir}/build/raw/%{file.relpath}"
|
||||||
}
|
}
|
||||||
filter {}
|
filter {}
|
||||||
|
|
||||||
|
filter "files:**/*.template"
|
||||||
|
buildmessage 'Templating %{file.relpath}'
|
||||||
|
buildcommands {
|
||||||
|
"echo \"%{cfg.targetdir}/build/raw/%{file.reldirectory}\""
|
||||||
|
}
|
||||||
|
buildoutputs {
|
||||||
|
"%{cfg.targetdir}/build/raw/%{file.relpath}"
|
||||||
|
}
|
||||||
|
filter {}
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user