Clean project structure.
This commit is contained in:
parent
78a4fa99ff
commit
947bf937fd
496 changed files with 206 additions and 137 deletions
28
src/base/compiler/CMakeLists.txt
Normal file
28
src/base/compiler/CMakeLists.txt
Normal file
|
@ -0,0 +1,28 @@
|
|||
set(MODULE_NAME compiler)
|
||||
|
||||
list(APPEND HEADERS
|
||||
Lexer.h
|
||||
template_engine/TemplatingEngine.h
|
||||
template_engine/TemplateFile.h
|
||||
template_engine/TemplateNode.h
|
||||
template_engine/TemplateElements.h
|
||||
)
|
||||
|
||||
list(APPEND SOURCES
|
||||
Lexer.cpp
|
||||
template_engine/TemplatingEngine.cpp
|
||||
template_engine/TemplateFile.cpp
|
||||
template_engine/TemplateNode.cpp
|
||||
template_engine/TemplateElements.cpp
|
||||
)
|
||||
|
||||
add_library(${MODULE_NAME} SHARED ${HEADERS} ${SOURCES})
|
||||
|
||||
target_include_directories(${MODULE_NAME} PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/template_engine
|
||||
)
|
||||
target_link_libraries( ${MODULE_NAME} PUBLIC core)
|
||||
|
||||
set_target_properties( ${MODULE_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER src/base)
|
72
src/base/compiler/Lexer.cpp
Normal file
72
src/base/compiler/Lexer.cpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
#include "Lexer.h"
|
||||
|
||||
bool Lexer::matchPattern(const std::string& pattern, const std::string& checkString, char delimiter, std::vector<std::string>& hitSequence)
|
||||
{
|
||||
if (checkString.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pattern.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool found_pattern = true;
|
||||
unsigned check_idx = 0;
|
||||
unsigned pattern_idx = 0;
|
||||
|
||||
std::vector<std::string> hits;
|
||||
std::string working_hit;
|
||||
while(check_idx < checkString.size())
|
||||
{
|
||||
if (pattern_idx == pattern.size())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
auto check_char = checkString[check_idx];
|
||||
auto pattern_char = pattern[pattern_idx];
|
||||
if (pattern_char == delimiter)
|
||||
{
|
||||
if (pattern_idx + 1 < pattern.size())
|
||||
{
|
||||
if (check_char == pattern[pattern_idx + 1])
|
||||
{
|
||||
hits.push_back(working_hit);
|
||||
working_hit.clear();
|
||||
pattern_idx++;
|
||||
}
|
||||
else
|
||||
{
|
||||
working_hit+=check_char;
|
||||
check_idx++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
working_hit+=check_char;
|
||||
check_idx++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (check_char == pattern_char)
|
||||
{
|
||||
check_idx++;
|
||||
pattern_idx++;
|
||||
}
|
||||
else
|
||||
{
|
||||
found_pattern = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found_pattern)
|
||||
{
|
||||
hitSequence = hits;
|
||||
}
|
||||
return found_pattern;
|
||||
}
|
11
src/base/compiler/Lexer.h
Normal file
11
src/base/compiler/Lexer.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class Lexer
|
||||
{
|
||||
public:
|
||||
// e.g. Pattern [@](@) returns <source, tag> for input: [source](tag) and delimiter @
|
||||
static bool matchPattern(const std::string& pattern, const std::string& checkString, char delimiter, std::vector<std::string>& hitSequence);
|
||||
};
|
172
src/base/compiler/template_engine/TemplateElements.cpp
Normal file
172
src/base/compiler/template_engine/TemplateElements.cpp
Normal file
|
@ -0,0 +1,172 @@
|
|||
#include "TemplateElements.h"
|
||||
|
||||
#include "StringUtils.h"
|
||||
#include "TemplateSubstitutionContext.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
TemplateExtends::TemplateExtends(TemplateNode* parent, const std::string& path)
|
||||
: TemplateNode(parent)
|
||||
{
|
||||
mPath = StringUtils::stripQuotes(path);
|
||||
};
|
||||
|
||||
std::string TemplateExtends::getRawContent() const
|
||||
{
|
||||
return "TemplateExtends: " + mPath;
|
||||
}
|
||||
|
||||
std::string TemplateExtends::getPath() const
|
||||
{
|
||||
return mPath;
|
||||
}
|
||||
|
||||
TemplateBlock::TemplateBlock(TemplateNode* parent, const std::string& name)
|
||||
: TemplateNode(parent),
|
||||
mName(name)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void TemplateBlock::addLine(const std::string& line)
|
||||
{
|
||||
mBody.push_back(line);
|
||||
}
|
||||
|
||||
std::string TemplateBlock::getRawContent() const
|
||||
{
|
||||
std::string content = "TemplateBlock: " + mName + " - Start \n";
|
||||
content += TemplateNode::getRawContent();
|
||||
content += "TemplateBlock: " + mName + " - End";
|
||||
return content;
|
||||
}
|
||||
|
||||
std::string TemplateBlock::getIdentifier() const
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
std::string TemplateBlock::renderAsParent(TemplateSubstitutionContext* substitutions, TemplateBlock* base)
|
||||
{
|
||||
std::string content;
|
||||
for (auto& child : mChildren)
|
||||
{
|
||||
if (child->getType() == Type::EXPRESSION)
|
||||
{
|
||||
auto expression = dynamic_cast<TemplateExpression*>(child.get());
|
||||
if (expression->getContent() == "super()")
|
||||
{
|
||||
content += base->render(substitutions, nullptr);
|
||||
}
|
||||
}
|
||||
else if(child->getType() == Type::TEXT_BODY)
|
||||
{
|
||||
content += child->render(substitutions, nullptr);
|
||||
}
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
std::string TemplateBlock::renderAsLeaf(TemplateSubstitutionContext* substitutions)
|
||||
{
|
||||
std::string content;
|
||||
for (auto& child : mChildren)
|
||||
{
|
||||
if(child->getType() == Type::TEXT_BODY)
|
||||
{
|
||||
content += child->render(substitutions, nullptr);
|
||||
}
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
std::string TemplateBlock::render(TemplateSubstitutionContext* substitutions, TemplateNode* parentContext)
|
||||
{
|
||||
std::string content;
|
||||
if (parentContext)
|
||||
{
|
||||
if (auto parent_node = parentContext->getFirstChildShallow(Type::BLOCK, getIdentifier()))
|
||||
{
|
||||
content = dynamic_cast<TemplateBlock*>(parent_node)->renderAsParent(substitutions, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
content= renderAsLeaf(substitutions);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
content= renderAsLeaf(substitutions);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
TemplateExpression::TemplateExpression(TemplateNode* parent, const std::string& content)
|
||||
: TemplateNode(parent),
|
||||
mContent(content)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
const std::string& TemplateExpression::getContent() const
|
||||
{
|
||||
return mContent;
|
||||
}
|
||||
|
||||
std::string TemplateExpression::render(TemplateSubstitutionContext* substitutions, TemplateNode* parentContext)
|
||||
{
|
||||
if (substitutions && substitutions->hasSubstitution(mContent))
|
||||
{
|
||||
return substitutions->getSubstitution(mContent);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string TemplateExpression::getRawContent() const
|
||||
{
|
||||
return "TemplateExpression: " + mContent;
|
||||
}
|
||||
|
||||
TemplateTextBody::TemplateTextBody(TemplateNode* parent)
|
||||
: TemplateNode(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void TemplateTextBody::addLine(const std::string& content)
|
||||
{
|
||||
mContent.push_back(content);
|
||||
}
|
||||
|
||||
bool TemplateTextBody::hasContent() const
|
||||
{
|
||||
return !mContent.empty();
|
||||
}
|
||||
|
||||
std::string TemplateTextBody::render(TemplateSubstitutionContext* substitutions, TemplateNode* parentContext)
|
||||
{
|
||||
std::string content;
|
||||
for(unsigned idx=0; idx<mContent.size(); idx++)
|
||||
{
|
||||
content += mContent[idx];
|
||||
if(idx != mContent.size() - 1)
|
||||
{
|
||||
content += '\n';
|
||||
}
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
std::string TemplateTextBody::getRawContent() const
|
||||
{
|
||||
std::string content;
|
||||
for(unsigned idx=0; idx<mContent.size(); idx++)
|
||||
{
|
||||
content += "Template Body L-" + std::to_string(idx) + ": " + mContent[idx];
|
||||
if(idx != mContent.size() - 1)
|
||||
{
|
||||
content += '\n';
|
||||
}
|
||||
}
|
||||
return content;
|
||||
}
|
96
src/base/compiler/template_engine/TemplateElements.h
Normal file
96
src/base/compiler/template_engine/TemplateElements.h
Normal file
|
@ -0,0 +1,96 @@
|
|||
#pragma once
|
||||
|
||||
#include "TemplateNode.h"
|
||||
|
||||
class TemplateExtends : public TemplateNode
|
||||
{
|
||||
public:
|
||||
TemplateExtends(TemplateNode* parent, const std::string& path);
|
||||
|
||||
virtual ~TemplateExtends() = default;
|
||||
|
||||
std::string getRawContent() const override;
|
||||
std::string getPath() const;
|
||||
|
||||
Type getType() const override
|
||||
{
|
||||
return Type::EXTENDS;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string mPath;
|
||||
};
|
||||
|
||||
class TemplateBlock : public TemplateNode
|
||||
{
|
||||
public:
|
||||
TemplateBlock(TemplateNode* parent, const std::string& name);
|
||||
|
||||
virtual ~TemplateBlock() = default;
|
||||
|
||||
void addLine(const std::string& line);
|
||||
|
||||
std::string getRawContent() const override;
|
||||
|
||||
std::string getIdentifier() const override;
|
||||
|
||||
Type getType() const override
|
||||
{
|
||||
return Type::BLOCK;
|
||||
}
|
||||
|
||||
std::string renderAsParent(TemplateSubstitutionContext* substitutions, TemplateBlock* base);
|
||||
|
||||
std::string renderAsLeaf(TemplateSubstitutionContext* substitutions);
|
||||
|
||||
std::string render(TemplateSubstitutionContext* substitutions, TemplateNode* parentContext) override;
|
||||
|
||||
private:
|
||||
std::string mName;
|
||||
std::vector<std::string> mBody;
|
||||
};
|
||||
|
||||
class TemplateExpression : public TemplateNode
|
||||
{
|
||||
public:
|
||||
TemplateExpression(TemplateNode* parent, const std::string& content);
|
||||
|
||||
virtual ~TemplateExpression() = default;
|
||||
|
||||
std::string getRawContent() const override;
|
||||
|
||||
const std::string& getContent() const;
|
||||
|
||||
Type getType() const override
|
||||
{
|
||||
return Type::EXPRESSION;
|
||||
}
|
||||
|
||||
std::string render(TemplateSubstitutionContext* substitutions, TemplateNode* parentContext) override;
|
||||
|
||||
private:
|
||||
std::string mContent;
|
||||
};
|
||||
|
||||
class TemplateTextBody : public TemplateNode
|
||||
{
|
||||
public:
|
||||
TemplateTextBody(TemplateNode* parent);
|
||||
|
||||
virtual ~TemplateTextBody() = default;
|
||||
|
||||
void addLine(const std::string& content);
|
||||
|
||||
std::string getRawContent() const override;
|
||||
|
||||
bool hasContent() const;
|
||||
|
||||
std::string render(TemplateSubstitutionContext* substitutions, TemplateNode* parentContext) override;
|
||||
|
||||
Type getType() const override
|
||||
{
|
||||
return Type::TEXT_BODY;
|
||||
}
|
||||
private:
|
||||
std::vector<std::string> mContent;
|
||||
};
|
207
src/base/compiler/template_engine/TemplateFile.cpp
Normal file
207
src/base/compiler/template_engine/TemplateFile.cpp
Normal file
|
@ -0,0 +1,207 @@
|
|||
#include "TemplateFile.h"
|
||||
|
||||
#include "TemplateElements.h"
|
||||
#include "TemplateNode.h"
|
||||
|
||||
#include "Lexer.h"
|
||||
#include "File.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
TemplateFile::TemplateFile(const Path& path)
|
||||
: mPath(path),
|
||||
mRootNode(std::make_unique<TemplateNode>(nullptr))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TemplateFile::~TemplateFile()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::string TemplateFile::getName() const
|
||||
{
|
||||
return mPath.stem().string();
|
||||
}
|
||||
|
||||
bool TemplateFile::hasLoaded() const
|
||||
{
|
||||
return mHasLoaded;
|
||||
}
|
||||
|
||||
TemplateNode* TemplateFile::getContent() const
|
||||
{
|
||||
return mRootNode.get();
|
||||
}
|
||||
|
||||
void TemplateFile::loadContent()
|
||||
{
|
||||
if (mHasLoaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
mRawContent = File(mPath).readLines();
|
||||
|
||||
mWorkingNode = mRootNode.get();
|
||||
mWorkingTextSpan = std::make_unique<TemplateTextBody>(mWorkingNode);
|
||||
for (const auto& line : mRawContent)
|
||||
{
|
||||
processLine(line);
|
||||
}
|
||||
onTextSpanFinished();
|
||||
|
||||
mHasLoaded = true;
|
||||
}
|
||||
|
||||
std::string TemplateFile::dumpContent()
|
||||
{
|
||||
return mRootNode->getRawContent();
|
||||
}
|
||||
|
||||
void TemplateFile::onTextSpanFinished()
|
||||
{
|
||||
if (!mWorkingLineContent.empty())
|
||||
{
|
||||
mWorkingTextSpan->addLine(mWorkingLineContent);
|
||||
}
|
||||
|
||||
if (mWorkingTextSpan->hasContent())
|
||||
{
|
||||
mWorkingNode->addChild(std::move(mWorkingTextSpan));
|
||||
mWorkingTextSpan = std::make_unique<TemplateTextBody>(mWorkingNode);
|
||||
}
|
||||
mWorkingLineContent.clear();
|
||||
}
|
||||
|
||||
std::size_t TemplateFile::checkForStatement(const std::string& lineSection)
|
||||
{
|
||||
if (lineSection.empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<std::string> hits;
|
||||
std::size_t hit_size{0};
|
||||
if (Lexer::matchPattern("{%@%}", lineSection, '@', hits))
|
||||
{
|
||||
if (hits.size() == 1)
|
||||
{
|
||||
auto content = hits[0];
|
||||
|
||||
onTextSpanFinished();
|
||||
|
||||
onFoundStatement(content);
|
||||
hit_size = 4 + content.size();
|
||||
}
|
||||
}
|
||||
return hit_size;
|
||||
}
|
||||
|
||||
std::size_t TemplateFile::checkForExpression(const std::string& lineSection)
|
||||
{
|
||||
if (lineSection.empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<std::string> hits;
|
||||
std::size_t hit_size{0};
|
||||
if (Lexer::matchPattern("{{@}}", lineSection, '@', hits))
|
||||
{
|
||||
if (hits.size() == 1)
|
||||
{
|
||||
auto content = hits[0];
|
||||
|
||||
onTextSpanFinished();
|
||||
|
||||
onFoundExpression(content);
|
||||
hit_size = 4 + content.size();
|
||||
}
|
||||
}
|
||||
return hit_size;
|
||||
}
|
||||
|
||||
void TemplateFile::processLine(const std::string& line)
|
||||
{
|
||||
std::size_t line_position = 0;
|
||||
mWorkingLineContent.clear();
|
||||
while(line_position < line.size())
|
||||
{
|
||||
const auto remaining = line.substr(line_position, line.size() - line_position);
|
||||
if(auto length = checkForStatement(remaining))
|
||||
{
|
||||
line_position += length;
|
||||
}
|
||||
else if(auto length = checkForExpression(remaining))
|
||||
{
|
||||
line_position += length;
|
||||
}
|
||||
else
|
||||
{
|
||||
mWorkingLineContent += line[line_position];
|
||||
line_position++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mWorkingLineContent.empty())
|
||||
{
|
||||
mWorkingTextSpan->addLine(mWorkingLineContent);
|
||||
mWorkingLineContent.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void TemplateFile::onFoundStatement(const std::string& statement_string)
|
||||
{
|
||||
const auto statement_elements = StringUtils::split(statement_string);
|
||||
if (statement_elements.size() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const auto statement_type = statement_elements[0];
|
||||
if (statement_type == "block" && statement_elements.size() == 2)
|
||||
{
|
||||
onFoundBlock(statement_elements);
|
||||
}
|
||||
else if (statement_type == "endblock")
|
||||
{
|
||||
onFoundEndBlock(statement_elements);
|
||||
}
|
||||
else if (statement_type == "extends")
|
||||
{
|
||||
onFoundExtends(statement_elements);
|
||||
}
|
||||
}
|
||||
|
||||
void TemplateFile::onFoundExpression(const std::string& expression_string)
|
||||
{
|
||||
const auto stripped = StringUtils::stripSurroundingWhitepsace(expression_string);
|
||||
auto expression = std::make_unique<TemplateExpression>(mWorkingNode, stripped);
|
||||
mWorkingNode->addChild(std::move(expression));
|
||||
}
|
||||
|
||||
void TemplateFile::onFoundBlock(const std::vector<std::string> args)
|
||||
{
|
||||
if (args.size() != 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto block = std::make_unique<TemplateBlock>(mWorkingNode, args[1]);
|
||||
auto temp = block.get();
|
||||
mWorkingNode->addChild(std::move(block));
|
||||
mWorkingNode = temp;
|
||||
}
|
||||
|
||||
void TemplateFile::onFoundEndBlock(const std::vector<std::string> args)
|
||||
{
|
||||
mWorkingNode = mWorkingNode->getParent();
|
||||
}
|
||||
|
||||
void TemplateFile::onFoundExtends(const std::vector<std::string> args)
|
||||
{
|
||||
if (args.size() != 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto extends = std::make_unique<TemplateExtends>(mWorkingNode, args[1]);
|
||||
mWorkingNode->addChild(std::move(extends));
|
||||
}
|
58
src/base/compiler/template_engine/TemplateFile.h
Normal file
58
src/base/compiler/template_engine/TemplateFile.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
|
||||
class TemplateNode;
|
||||
class TemplateTextBody;
|
||||
|
||||
using Path = std::filesystem::path;
|
||||
|
||||
class TemplateFile
|
||||
{
|
||||
public:
|
||||
TemplateFile(const Path& path);
|
||||
|
||||
~TemplateFile();
|
||||
|
||||
std::string dumpContent();
|
||||
|
||||
std::string getName() const;
|
||||
|
||||
TemplateNode* getContent() const;
|
||||
|
||||
bool hasLoaded() const;
|
||||
|
||||
void loadContent();
|
||||
|
||||
private:
|
||||
std::size_t checkForStatement(const std::string& lineSection);
|
||||
|
||||
std::size_t checkForExpression(const std::string& lineSection);
|
||||
|
||||
void onTextSpanFinished();
|
||||
|
||||
void onFoundStatement(const std::string& statement_string);
|
||||
|
||||
void onFoundExpression(const std::string& expression_string);
|
||||
|
||||
void onFoundBlock(const std::vector<std::string> args);
|
||||
|
||||
void onFoundEndBlock(const std::vector<std::string> args);
|
||||
|
||||
void onFoundExtends(const std::vector<std::string> args);
|
||||
|
||||
void processLine(const std::string& line);
|
||||
|
||||
Path mPath;
|
||||
std::string mParentName;
|
||||
std::vector<std::string> mRawContent;
|
||||
bool mHasLoaded{false};
|
||||
|
||||
std::unique_ptr<TemplateNode> mRootNode;
|
||||
TemplateNode* mWorkingNode{ nullptr };
|
||||
|
||||
std::string mWorkingLineContent;
|
||||
std::unique_ptr<TemplateTextBody> mWorkingTextSpan;
|
||||
};
|
101
src/base/compiler/template_engine/TemplateNode.cpp
Normal file
101
src/base/compiler/template_engine/TemplateNode.cpp
Normal file
|
@ -0,0 +1,101 @@
|
|||
#include "TemplateNode.h"
|
||||
|
||||
#include "TemplateSubstitutionContext.h"
|
||||
|
||||
TemplateNode::TemplateNode(TemplateNode* parent)
|
||||
: mParent(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TemplateNode* TemplateNode::getParent() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
void TemplateNode::addChild(std::unique_ptr<TemplateNode> child)
|
||||
{
|
||||
mChildren.push_back(std::move(child));
|
||||
}
|
||||
|
||||
std::size_t TemplateNode::getNumChildren() const
|
||||
{
|
||||
return mChildren.size();
|
||||
}
|
||||
|
||||
TemplateNode* TemplateNode::getFirstChildShallow(Type type, const std::string& identifier) const
|
||||
{
|
||||
for (const auto& child : mChildren)
|
||||
{
|
||||
if (child->getType() == type)
|
||||
{
|
||||
if (!identifier.empty())
|
||||
{
|
||||
if (child->getIdentifier() == identifier)
|
||||
{
|
||||
return child.get();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return child.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TemplateNode::Type TemplateNode::getType() const
|
||||
{
|
||||
return Type::NONE;
|
||||
}
|
||||
|
||||
std::string TemplateNode::getIdentifier() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
TemplateNode* TemplateNode::getChild(std::size_t index) const
|
||||
{
|
||||
return mChildren[index].get();
|
||||
}
|
||||
|
||||
std::string TemplateNode::getRawContent() const
|
||||
{
|
||||
std::string content;
|
||||
for (const auto& child : mChildren)
|
||||
{
|
||||
content += child->getRawContent() + "\n";
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
void TemplateNode::setExtensionParent(TemplateNode* parent)
|
||||
{
|
||||
mExtensionParent = parent;
|
||||
}
|
||||
|
||||
void TemplateNode::setExtensionBase(TemplateNode* base)
|
||||
{
|
||||
mExtensionBase = base;
|
||||
}
|
||||
|
||||
std::string TemplateNode::render(TemplateSubstitutionContext* substitutions, TemplateNode* parentContext)
|
||||
{
|
||||
if (mExtensionBase)
|
||||
{
|
||||
return mExtensionBase->render(substitutions, this);
|
||||
}
|
||||
|
||||
if (!parentContext && mExtensionParent)
|
||||
{
|
||||
parentContext = mExtensionParent;
|
||||
}
|
||||
|
||||
std::string content;
|
||||
for (size_t idx = 0; idx < mChildren.size(); idx++)
|
||||
{
|
||||
content += mChildren[idx]->render(substitutions, parentContext);
|
||||
}
|
||||
return content;
|
||||
}
|
54
src/base/compiler/template_engine/TemplateNode.h
Normal file
54
src/base/compiler/template_engine/TemplateNode.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class TemplateSubstitutionContext;
|
||||
|
||||
class TemplateNode
|
||||
{
|
||||
public:
|
||||
enum class Type
|
||||
{
|
||||
NONE,
|
||||
BLOCK,
|
||||
EXPRESSION,
|
||||
EXTENDS,
|
||||
TEXT_BODY
|
||||
};
|
||||
|
||||
TemplateNode(TemplateNode* parent);
|
||||
|
||||
virtual ~TemplateNode() = default;
|
||||
|
||||
virtual void addChild(std::unique_ptr<TemplateNode> child);
|
||||
|
||||
TemplateNode* getChild(std::size_t index) const;
|
||||
|
||||
TemplateNode* getFirstChildShallow(Type type, const std::string& identifier = {}) const;
|
||||
|
||||
virtual std::string getIdentifier() const;
|
||||
|
||||
std::size_t getNumChildren() const;
|
||||
|
||||
TemplateNode* getParent() const;
|
||||
|
||||
virtual std::string getRawContent() const;
|
||||
|
||||
virtual Type getType() const;
|
||||
|
||||
virtual std::string render(TemplateSubstitutionContext* substitutions, TemplateNode* parentContext = nullptr);
|
||||
|
||||
void setExtensionParent(TemplateNode* parent);
|
||||
|
||||
void setExtensionBase(TemplateNode* base);
|
||||
|
||||
protected:
|
||||
std::vector<std::unique_ptr<TemplateNode> > mChildren;
|
||||
TemplateNode* mParent{ nullptr };
|
||||
TemplateNode* mExtensionParent{ nullptr };
|
||||
TemplateNode* mExtensionBase{ nullptr };
|
||||
};
|
||||
|
||||
using TemplateNodePtr = std::unique_ptr<TemplateNode>;
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
class TemplateSubstitutionContext
|
||||
{
|
||||
public:
|
||||
|
||||
void addSubstitution(const std::string& key, const std::string& value)
|
||||
{
|
||||
mSubstitutions[key] = value;
|
||||
}
|
||||
|
||||
bool hasSubstitution(const std::string& key) const
|
||||
{
|
||||
return mSubstitutions.find(key) != mSubstitutions.end();
|
||||
}
|
||||
|
||||
std::string getSubstitution(const std::string& key) const
|
||||
{
|
||||
auto iter = mSubstitutions.find(key);
|
||||
if(iter != mSubstitutions.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, std::string> mSubstitutions;
|
||||
};
|
80
src/base/compiler/template_engine/TemplatingEngine.cpp
Normal file
80
src/base/compiler/template_engine/TemplatingEngine.cpp
Normal file
|
@ -0,0 +1,80 @@
|
|||
#include "TemplatingEngine.h"
|
||||
|
||||
#include "Directory.h"
|
||||
#include "FileLogger.h"
|
||||
|
||||
#include "TemplateElements.h"
|
||||
#include "TemplateSubstitutionContext.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
TemplatingEngine::TemplatingEngine(const Path& workingDirectory)
|
||||
: mWorkingDirectory(workingDirectory)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::string TemplatingEngine::renderTemplate(const std::string& name, TemplateSubstitutionContext* substitutionContext)
|
||||
{
|
||||
if (mTemplateFiles.empty())
|
||||
{
|
||||
loadTemplateFiles();
|
||||
}
|
||||
|
||||
if (auto file = getTemplateFile(name))
|
||||
{
|
||||
if (!file->hasLoaded())
|
||||
{
|
||||
file->loadContent();
|
||||
//std::cout << file->dumpContent();
|
||||
|
||||
processTemplate(file, nullptr);
|
||||
}
|
||||
return file->getContent()->render(substitutionContext, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
void TemplatingEngine::loadTemplateFiles()
|
||||
{
|
||||
const auto files = Directory::getFilesWithExtension(mWorkingDirectory, mTemplateExtension);
|
||||
for (const auto& path : files)
|
||||
{
|
||||
mTemplateFiles[path.stem().string()] = std::make_unique<TemplateFile>(path);
|
||||
}
|
||||
MLOG_INFO("Found: " << mTemplateFiles.size() << " templates in " << mWorkingDirectory);
|
||||
}
|
||||
|
||||
TemplateFile* TemplatingEngine::getTemplateFile(const Path& path)
|
||||
{
|
||||
return getTemplateFile(path.stem().string());
|
||||
}
|
||||
|
||||
TemplateFile* TemplatingEngine::getTemplateFile(const std::string& name)
|
||||
{
|
||||
return mTemplateFiles[name].get();
|
||||
}
|
||||
|
||||
void TemplatingEngine::processTemplate(TemplateFile* file, TemplateNode* parent)
|
||||
{
|
||||
auto content = file->getContent();
|
||||
if (parent)
|
||||
{
|
||||
content->setExtensionParent(parent);
|
||||
parent->setExtensionBase(content);
|
||||
}
|
||||
|
||||
if (auto extension_node = dynamic_cast<TemplateExtends*>(content->getFirstChildShallow(TemplateNode::Type::EXTENDS)))
|
||||
{
|
||||
if (auto extension_template = getTemplateFile(Path(extension_node->getPath())))
|
||||
{
|
||||
extension_template->loadContent();
|
||||
//std::cout << extension_template->dumpContent();
|
||||
|
||||
processTemplate(extension_template, content);
|
||||
}
|
||||
}
|
||||
}
|
30
src/base/compiler/template_engine/TemplatingEngine.h
Normal file
30
src/base/compiler/template_engine/TemplatingEngine.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include "File.h"
|
||||
#include "TemplateFile.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
class TemplateSubstitutionContext;
|
||||
|
||||
class TemplatingEngine
|
||||
{
|
||||
public:
|
||||
TemplatingEngine(const Path& workingDirectory);
|
||||
|
||||
std::string renderTemplate(const std::string& name, TemplateSubstitutionContext* substitutionContext);
|
||||
|
||||
private:
|
||||
TemplateFile* getTemplateFile(const std::string& name);
|
||||
TemplateFile* getTemplateFile(const Path& path);
|
||||
|
||||
void loadTemplateFiles();
|
||||
void processTemplate(TemplateFile* file, TemplateNode* parent = nullptr);
|
||||
|
||||
std::unordered_map<std::string, std::unique_ptr<TemplateFile> > mTemplateFiles;
|
||||
Path mWorkingDirectory;
|
||||
std::string mTemplateExtension{ ".html" };
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue