Toward template rendering.
This commit is contained in:
parent
eb3b394bdf
commit
350c20efa6
9 changed files with 542 additions and 385 deletions
|
@ -1,11 +1,15 @@
|
||||||
list(APPEND compiler_HEADERS
|
list(APPEND compiler_HEADERS
|
||||||
Lexer.h
|
Lexer.h
|
||||||
TemplatingEngine.h
|
TemplatingEngine.h
|
||||||
|
TemplateFile.h
|
||||||
|
TemplateNodes.h
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND compiler_LIB_INCLUDES
|
list(APPEND compiler_LIB_INCLUDES
|
||||||
Lexer.cpp
|
Lexer.cpp
|
||||||
TemplatingEngine.cpp
|
TemplatingEngine.cpp
|
||||||
|
TemplateFile.cpp
|
||||||
|
TemplateNodes.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(compiler SHARED ${compiler_LIB_INCLUDES} ${compiler_HEADERS})
|
add_library(compiler SHARED ${compiler_LIB_INCLUDES} ${compiler_HEADERS})
|
||||||
|
|
187
src/compiler/TemplateFile.cpp
Normal file
187
src/compiler/TemplateFile.cpp
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
#include "TemplateFile.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
TemplateFile::TemplateFile(const Path& path)
|
||||||
|
: mPath(path),
|
||||||
|
mRootNode(std::make_unique<TemplateNode>(nullptr))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> TemplateFile::getProcessedContent() const
|
||||||
|
{
|
||||||
|
return mProcessedContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string TemplateFile::getName() const
|
||||||
|
{
|
||||||
|
return mPath.stem().string();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TemplateFile::loadContent()
|
||||||
|
{
|
||||||
|
std::cout << "Trying to load file at: " << mPath << std::endl;
|
||||||
|
mRawContent = File(mPath).readLines();
|
||||||
|
mWorkingLine = 0;
|
||||||
|
mWorkingNode = mRootNode.get();
|
||||||
|
mWorkingTextBody = std::make_unique<TemplateTextBody>(mWorkingNode);
|
||||||
|
for (const auto& line : mRawContent)
|
||||||
|
{
|
||||||
|
processLine(line);
|
||||||
|
mWorkingLine++;
|
||||||
|
}
|
||||||
|
onTextBodyFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TemplateFile::onTextBodyFinished(std::string working_string)
|
||||||
|
{
|
||||||
|
if (!working_string.empty())
|
||||||
|
{
|
||||||
|
mWorkingTextBody->addLine(working_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mWorkingTextBody->hasContent())
|
||||||
|
{
|
||||||
|
mWorkingNode->addChild(std::move(mWorkingTextBody));
|
||||||
|
mWorkingTextBody = std::make_unique<TemplateTextBody>(mWorkingNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TemplateFile::processLine(const std::string& line)
|
||||||
|
{
|
||||||
|
bool last_was_ldelimiter{ false };
|
||||||
|
bool last_was_statement_rdelimiter{ false };
|
||||||
|
bool last_was_expression_rdelimiter{ false };
|
||||||
|
bool in_statement{ false };
|
||||||
|
bool in_expression{ false };
|
||||||
|
std::string working_string;
|
||||||
|
std::string last_working_string;
|
||||||
|
for (auto c : line)
|
||||||
|
{
|
||||||
|
if (c == '{')
|
||||||
|
{
|
||||||
|
if (last_was_ldelimiter)
|
||||||
|
{
|
||||||
|
in_expression = true;
|
||||||
|
last_was_ldelimiter = false;
|
||||||
|
working_string = "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
last_was_ldelimiter = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c == '%' && last_was_ldelimiter)
|
||||||
|
{
|
||||||
|
last_was_ldelimiter = false;
|
||||||
|
in_statement = true;
|
||||||
|
last_working_string = working_string;
|
||||||
|
working_string = "";
|
||||||
|
}
|
||||||
|
else if (c == '%' && in_statement)
|
||||||
|
{
|
||||||
|
last_was_statement_rdelimiter = true;
|
||||||
|
}
|
||||||
|
else if (c == '}' && (last_was_statement_rdelimiter || in_expression || last_was_expression_rdelimiter))
|
||||||
|
{
|
||||||
|
if (last_was_statement_rdelimiter)
|
||||||
|
{
|
||||||
|
onTextBodyFinished(last_working_string);
|
||||||
|
onFoundStatement(working_string);
|
||||||
|
last_was_statement_rdelimiter = false;
|
||||||
|
working_string = "";
|
||||||
|
}
|
||||||
|
else if (in_expression)
|
||||||
|
{
|
||||||
|
last_was_expression_rdelimiter = true;
|
||||||
|
in_expression = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
onTextBodyFinished();
|
||||||
|
onFoundExpression(working_string);
|
||||||
|
last_was_expression_rdelimiter = false;
|
||||||
|
working_string = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (last_was_ldelimiter && (!in_statement && !in_expression))
|
||||||
|
{
|
||||||
|
last_was_ldelimiter = false;
|
||||||
|
working_string += '{';
|
||||||
|
working_string += c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
working_string += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!working_string.empty())
|
||||||
|
{
|
||||||
|
mWorkingTextBody->addLine(working_string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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::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));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TemplateFile::onFoundExpression(const std::string& expression_string)
|
||||||
|
{
|
||||||
|
auto expression = std::make_unique<TemplateExpression>(mWorkingNode, expression_string);
|
||||||
|
mWorkingNode->addChild(std::move(expression));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TemplateFile::dumpContent()
|
||||||
|
{
|
||||||
|
auto content = mRootNode->getRawContent();
|
||||||
|
std::cout << content << std::endl;
|
||||||
|
}
|
50
src/compiler/TemplateFile.h
Normal file
50
src/compiler/TemplateFile.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "File.h"
|
||||||
|
|
||||||
|
#include "TemplateNodes.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class TemplateFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TemplateFile(const Path& path);
|
||||||
|
|
||||||
|
std::vector<std::string> getProcessedContent() const;
|
||||||
|
|
||||||
|
std::string getName() const;
|
||||||
|
|
||||||
|
void loadContent();
|
||||||
|
|
||||||
|
void onTextBodyFinished(std::string working_string = {});
|
||||||
|
|
||||||
|
void processLine(const std::string& line);
|
||||||
|
|
||||||
|
void onFoundStatement(const std::string& statement_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 onFoundExpression(const std::string& expression_string);
|
||||||
|
|
||||||
|
void dumpContent();
|
||||||
|
|
||||||
|
TemplateNode* getContent() const
|
||||||
|
{
|
||||||
|
return mRootNode.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Path mPath;
|
||||||
|
unsigned mWorkingLine{ 0 };
|
||||||
|
std::string mParentName;
|
||||||
|
std::vector<std::string> mRawContent;
|
||||||
|
std::vector<std::string> mProcessedContent;
|
||||||
|
std::unique_ptr<TemplateNode> mRootNode;
|
||||||
|
TemplateNode* mWorkingNode{ nullptr };
|
||||||
|
std::unique_ptr<TemplateTextBody> mWorkingTextBody;
|
||||||
|
};
|
0
src/compiler/TemplateNodes.cpp
Normal file
0
src/compiler/TemplateNodes.cpp
Normal file
190
src/compiler/TemplateNodes.h
Normal file
190
src/compiler/TemplateNodes.h
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
class TemplateNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
TemplateNode(TemplateNode* parent)
|
||||||
|
: mParent(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TemplateNode* getParent() const
|
||||||
|
{
|
||||||
|
return mParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void addChild(std::unique_ptr<TemplateNode> child)
|
||||||
|
{
|
||||||
|
mChildren.push_back(std::move(child));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t getNumChildren() const
|
||||||
|
{
|
||||||
|
return mChildren.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
TemplateNode* getChild(std::size_t index) const
|
||||||
|
{
|
||||||
|
return mChildren[index].get();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string getRawContent() const
|
||||||
|
{
|
||||||
|
std::string content;
|
||||||
|
for (const auto& child : mChildren)
|
||||||
|
{
|
||||||
|
content += child->getRawContent() + "\n";
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T* getFirstChildShallow() const
|
||||||
|
{
|
||||||
|
for (const auto& child : mChildren)
|
||||||
|
{
|
||||||
|
if (auto ret = dynamic_cast<T*>(child.get()))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setExtensionParent(TemplateNode* parent)
|
||||||
|
{
|
||||||
|
mExtensionParent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string render()
|
||||||
|
{
|
||||||
|
std::string content;
|
||||||
|
for (size_t idx = 0; idx < mChildren.size(); idx++)
|
||||||
|
{
|
||||||
|
content += mChildren[idx]->render();
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::vector<std::unique_ptr<TemplateNode> > mChildren;
|
||||||
|
TemplateNode* mParent{ nullptr };
|
||||||
|
TemplateNode* mExtensionParent{ nullptr };
|
||||||
|
};
|
||||||
|
|
||||||
|
using TemplateNodePtr = std::unique_ptr<TemplateNode>;
|
||||||
|
|
||||||
|
class TemplateExtends : public TemplateNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TemplateExtends(TemplateNode* parent, const std::string& path)
|
||||||
|
: TemplateNode(parent),
|
||||||
|
mPath(path)
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string getRawContent() const override
|
||||||
|
{
|
||||||
|
return "TemplateExtends: " + mPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getPath() const
|
||||||
|
{
|
||||||
|
return mPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string mPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TemplateBlock : public TemplateNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TemplateBlock(TemplateNode* parent, const std::string& name)
|
||||||
|
: TemplateNode(parent),
|
||||||
|
mName(name)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void addLine(const std::string& line)
|
||||||
|
{
|
||||||
|
mBody.push_back(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getRawContent() const override
|
||||||
|
{
|
||||||
|
std::string content = "TemplateBlock: " + mName + "\n";
|
||||||
|
content += TemplateNode::getRawContent();
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string mName;
|
||||||
|
std::vector<std::string> mBody;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TemplateExpression : public TemplateNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TemplateExpression(TemplateNode* parent, const std::string& content)
|
||||||
|
: TemplateNode(parent),
|
||||||
|
mContent(content)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getRawContent() const override
|
||||||
|
{
|
||||||
|
return "TemplateExpression: " + mContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string mContent;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TemplateTextBody : public TemplateNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TemplateTextBody(TemplateNode* parent)
|
||||||
|
: TemplateNode(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void addLine(const std::string& content)
|
||||||
|
{
|
||||||
|
mContent.push_back(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasContent() const
|
||||||
|
{
|
||||||
|
return !mContent.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string render() override
|
||||||
|
{
|
||||||
|
std::string content;
|
||||||
|
for (const auto& line : mContent)
|
||||||
|
{
|
||||||
|
content += line;
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getRawContent() const override
|
||||||
|
{
|
||||||
|
std::string content;
|
||||||
|
for (const auto& line : mContent)
|
||||||
|
{
|
||||||
|
content += "TemplateBody: " + line + "\n";
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::string> mContent;
|
||||||
|
};
|
|
@ -0,0 +1,82 @@
|
||||||
|
#include "TemplatingEngine.h"
|
||||||
|
|
||||||
|
#include "Directory.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
TemplatingEngine::TemplatingEngine(const Path& workingDirectory)
|
||||||
|
: mWorkingDirectory(workingDirectory)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TemplatingEngine::loadTemplateFiles()
|
||||||
|
{
|
||||||
|
const auto files = Directory::getFilesWithExtension(mWorkingDirectory, mTemplateExtension);
|
||||||
|
for (const auto& file : files)
|
||||||
|
{
|
||||||
|
mTemplateFiles.push_back(std::make_unique<TemplateFile>(file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string TemplatingEngine::processTemplate(const std::string& name)
|
||||||
|
{
|
||||||
|
if (auto file = getTemplateFile(name))
|
||||||
|
{
|
||||||
|
return processTemplate(file);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
TemplateFile* TemplatingEngine::getTemplateFile(const Path& path)
|
||||||
|
{
|
||||||
|
return getTemplateFile(path.stem().string());
|
||||||
|
}
|
||||||
|
|
||||||
|
TemplateFile* TemplatingEngine::getTemplateFile(const std::string& name)
|
||||||
|
{
|
||||||
|
std::cout << "Looking for template file with name: " << name << std::endl;
|
||||||
|
for (const auto& file : mTemplateFiles)
|
||||||
|
{
|
||||||
|
if (file->getName() == name)
|
||||||
|
{
|
||||||
|
return file.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string TemplatingEngine::processTemplate(TemplateFile* file, TemplateNode* parent)
|
||||||
|
{
|
||||||
|
file->loadContent();
|
||||||
|
file->dumpContent();
|
||||||
|
|
||||||
|
auto content = file->getContent();
|
||||||
|
if (parent)
|
||||||
|
{
|
||||||
|
content->setExtensionParent(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto extension_node = content->getFirstChildShallow<TemplateExtends>())
|
||||||
|
{
|
||||||
|
std::cout << "Found extension node" << std::endl;
|
||||||
|
if (auto extension_template = getTemplateFile(Path(extension_node->getPath())))
|
||||||
|
{
|
||||||
|
std::cout << "Found extension template" << std::endl;
|
||||||
|
return processTemplate(extension_template, parent);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return render(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return render(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string TemplatingEngine::render(TemplateNode* content)
|
||||||
|
{
|
||||||
|
return content->render();
|
||||||
|
}
|
|
@ -1,399 +1,28 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "File.h"
|
#include "File.h"
|
||||||
#include "Directory.h"
|
#include "TemplateFile.h"
|
||||||
#include "StringUtils.h"
|
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <sstream>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
class TemplateNode
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
TemplateNode(TemplateNode* parent)
|
|
||||||
: mParent(parent)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
TemplateNode* getParent() const
|
|
||||||
{
|
|
||||||
return mParent;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void addChild(std::unique_ptr<TemplateNode> child)
|
|
||||||
{
|
|
||||||
mChildren.push_back(std::move(child));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t getNumChildren() const
|
|
||||||
{
|
|
||||||
return mChildren.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
TemplateNode* getChild(std::size_t index) const
|
|
||||||
{
|
|
||||||
return mChildren[index].get();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual std::string getRawContent() const
|
|
||||||
{
|
|
||||||
std::string content;
|
|
||||||
for (const auto& child : mChildren)
|
|
||||||
{
|
|
||||||
content += child->getRawContent() + "\n";
|
|
||||||
}
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
std::vector<std::unique_ptr<TemplateNode> > mChildren;
|
|
||||||
TemplateNode* mParent{ nullptr };
|
|
||||||
};
|
|
||||||
|
|
||||||
using TemplateNodePtr = std::unique_ptr<TemplateNode>;
|
|
||||||
|
|
||||||
class TemplateExtends : public TemplateNode
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TemplateExtends(TemplateNode* parent, const std::string& path)
|
|
||||||
: TemplateNode(parent),
|
|
||||||
mPath(path)
|
|
||||||
{
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string getRawContent() const override
|
|
||||||
{
|
|
||||||
return "TemplateExtends: " + mPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string mPath;
|
|
||||||
};
|
|
||||||
|
|
||||||
class TemplateBlock : public TemplateNode
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TemplateBlock(TemplateNode* parent, const std::string& name)
|
|
||||||
: TemplateNode(parent),
|
|
||||||
mName(name)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void addLine(const std::string& line)
|
|
||||||
{
|
|
||||||
mBody.push_back(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string getRawContent() const override
|
|
||||||
{
|
|
||||||
std::string content = "TemplateBlock: " + mName + "\n";
|
|
||||||
content += TemplateNode::getRawContent();
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string mName;
|
|
||||||
std::vector<std::string> mBody;
|
|
||||||
};
|
|
||||||
|
|
||||||
class TemplateExpression : public TemplateNode
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TemplateExpression(TemplateNode* parent, const std::string& content)
|
|
||||||
: TemplateNode(parent),
|
|
||||||
mContent(content)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string getRawContent() const override
|
|
||||||
{
|
|
||||||
return "TemplateExpression: " + mContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string mContent;
|
|
||||||
};
|
|
||||||
|
|
||||||
class TemplateTextBody : public TemplateNode
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TemplateTextBody(TemplateNode* parent)
|
|
||||||
: TemplateNode(parent)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void addLine(const std::string& content)
|
|
||||||
{
|
|
||||||
mContent.push_back(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasContent() const
|
|
||||||
{
|
|
||||||
return !mContent.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string getRawContent() const override
|
|
||||||
{
|
|
||||||
std::string content;
|
|
||||||
for (const auto& line : mContent)
|
|
||||||
{
|
|
||||||
content += "TemplateBody: " + line + "\n";
|
|
||||||
}
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<std::string> mContent;
|
|
||||||
};
|
|
||||||
|
|
||||||
class TemplateFile
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TemplateFile(const Path& path)
|
|
||||||
: mPath(path),
|
|
||||||
mRootNode(std::make_unique<TemplateNode>(nullptr))
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> getProcessedContent() const
|
|
||||||
{
|
|
||||||
return mProcessedContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string getName() const
|
|
||||||
{
|
|
||||||
return mPath.stem().string();
|
|
||||||
}
|
|
||||||
|
|
||||||
void loadContent()
|
|
||||||
{
|
|
||||||
std::cout << "Trying to load file at: " << mPath << std::endl;
|
|
||||||
mRawContent = File(mPath).readLines();
|
|
||||||
mWorkingLine = 0;
|
|
||||||
mWorkingNode = mRootNode.get();
|
|
||||||
mWorkingTextBody = std::make_unique<TemplateTextBody>(mWorkingNode);
|
|
||||||
for (const auto& line : mRawContent)
|
|
||||||
{
|
|
||||||
processLine(line);
|
|
||||||
mWorkingLine++;
|
|
||||||
}
|
|
||||||
onTextBodyFinished();
|
|
||||||
}
|
|
||||||
|
|
||||||
void onTextBodyFinished(std::string working_string = {})
|
|
||||||
{
|
|
||||||
if (!working_string.empty())
|
|
||||||
{
|
|
||||||
mWorkingTextBody->addLine(working_string);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mWorkingTextBody->hasContent())
|
|
||||||
{
|
|
||||||
mWorkingNode->addChild(std::move(mWorkingTextBody));
|
|
||||||
mWorkingTextBody = std::make_unique<TemplateTextBody>(mWorkingNode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void processLine(const std::string& line)
|
|
||||||
{
|
|
||||||
bool last_was_ldelimiter{ false };
|
|
||||||
bool last_was_statement_rdelimiter{ false };
|
|
||||||
bool last_was_expression_rdelimiter{ false };
|
|
||||||
bool in_statement{ false };
|
|
||||||
bool in_expression{ false };
|
|
||||||
std::string working_string;
|
|
||||||
std::string last_working_string;
|
|
||||||
for (auto c : line)
|
|
||||||
{
|
|
||||||
if (c == '{')
|
|
||||||
{
|
|
||||||
if (last_was_ldelimiter)
|
|
||||||
{
|
|
||||||
in_expression = true;
|
|
||||||
last_was_ldelimiter = false;
|
|
||||||
working_string = "";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
last_was_ldelimiter = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (c == '%' && last_was_ldelimiter)
|
|
||||||
{
|
|
||||||
last_was_ldelimiter = false;
|
|
||||||
in_statement = true;
|
|
||||||
last_working_string = working_string;
|
|
||||||
working_string = "";
|
|
||||||
}
|
|
||||||
else if (c == '%' && in_statement)
|
|
||||||
{
|
|
||||||
last_was_statement_rdelimiter = true;
|
|
||||||
}
|
|
||||||
else if (c == '}' && (last_was_statement_rdelimiter || in_expression || last_was_expression_rdelimiter))
|
|
||||||
{
|
|
||||||
if (last_was_statement_rdelimiter)
|
|
||||||
{
|
|
||||||
onTextBodyFinished(last_working_string);
|
|
||||||
onFoundStatement(working_string);
|
|
||||||
last_was_statement_rdelimiter = false;
|
|
||||||
working_string = "";
|
|
||||||
}
|
|
||||||
else if (in_expression)
|
|
||||||
{
|
|
||||||
last_was_expression_rdelimiter = true;
|
|
||||||
in_expression = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
onTextBodyFinished();
|
|
||||||
onFoundExpression(working_string);
|
|
||||||
last_was_expression_rdelimiter = false;
|
|
||||||
working_string = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (last_was_ldelimiter && (!in_statement && !in_expression))
|
|
||||||
{
|
|
||||||
last_was_ldelimiter = false;
|
|
||||||
working_string += '{';
|
|
||||||
working_string += c;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
working_string += c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!working_string.empty())
|
|
||||||
{
|
|
||||||
mWorkingTextBody->addLine(working_string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void 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 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 onFoundEndBlock(const std::vector<std::string> args)
|
|
||||||
{
|
|
||||||
mWorkingNode = mWorkingNode->getParent();
|
|
||||||
}
|
|
||||||
|
|
||||||
void 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
void onFoundExpression(const std::string& expression_string)
|
|
||||||
{
|
|
||||||
auto expression = std::make_unique<TemplateExpression>(mWorkingNode, expression_string);
|
|
||||||
mWorkingNode->addChild(std::move(expression));
|
|
||||||
}
|
|
||||||
|
|
||||||
void dumpContent()
|
|
||||||
{
|
|
||||||
auto content = mRootNode->getRawContent();
|
|
||||||
std::cout << content << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Path mPath;
|
|
||||||
unsigned mWorkingLine{ 0 };
|
|
||||||
std::string mParentName;
|
|
||||||
std::vector<std::string> mRawContent;
|
|
||||||
std::vector<std::string> mProcessedContent;
|
|
||||||
std::unique_ptr<TemplateNode> mRootNode;
|
|
||||||
TemplateNode* mWorkingNode{ nullptr };
|
|
||||||
std::unique_ptr<TemplateTextBody> mWorkingTextBody;
|
|
||||||
};
|
|
||||||
|
|
||||||
class TemplatingEngine
|
class TemplatingEngine
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TemplatingEngine(const Path& workingDirectory)
|
TemplatingEngine(const Path& workingDirectory);
|
||||||
: mWorkingDirectory(workingDirectory)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void loadTemplateFiles()
|
|
||||||
{
|
|
||||||
const auto files = Directory::getFilesWithExtension(mWorkingDirectory, mTemplateExtension);
|
|
||||||
for (const auto& file : files)
|
|
||||||
{
|
|
||||||
mTemplateFiles.push_back(TemplateFile(file));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void processTemplate(const std::string& name)
|
|
||||||
{
|
|
||||||
for (auto& file : mTemplateFiles)
|
|
||||||
{
|
|
||||||
const auto filename = file.getName();
|
|
||||||
if (filename == name)
|
|
||||||
{
|
|
||||||
processTemplate(file);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void processTemplate(TemplateFile& file)
|
|
||||||
{
|
|
||||||
file.loadContent();
|
|
||||||
file.dumpContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
void loadTemplateFiles();
|
||||||
|
|
||||||
|
std::string processTemplate(const std::string& name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<TemplateFile> mTemplateFiles;
|
TemplateFile* getTemplateFile(const std::string& name);
|
||||||
|
TemplateFile* getTemplateFile(const Path& path);
|
||||||
|
std::string render(TemplateNode* content);
|
||||||
|
|
||||||
|
std::string processTemplate(TemplateFile* file, TemplateNode* parent = nullptr);
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<TemplateFile> > mTemplateFiles;
|
||||||
Path mWorkingDirectory;
|
Path mWorkingDirectory;
|
||||||
std::string mTemplateExtension{ ".html" };
|
std::string mTemplateExtension{ ".html" };
|
||||||
};
|
};
|
|
@ -76,7 +76,20 @@ FileFormat::Format File::InferFormat() const
|
||||||
|
|
||||||
void File::WriteText(const std::string& text)
|
void File::WriteText(const std::string& text)
|
||||||
{
|
{
|
||||||
|
bool had_to_open{ false };
|
||||||
|
if (!mOutHandle)
|
||||||
|
{
|
||||||
|
had_to_open = true;
|
||||||
|
SetAccessMode(File::AccessMode::Write);
|
||||||
|
Open();
|
||||||
|
}
|
||||||
|
|
||||||
(*mOutHandle) << text;
|
(*mOutHandle) << text;
|
||||||
|
|
||||||
|
if (had_to_open)
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> File::readLines()
|
std::vector<std::string> File::readLines()
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "TemplatingEngine.h"
|
#include "TemplatingEngine.h"
|
||||||
|
|
||||||
|
#include <File.h>
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
@ -9,8 +11,8 @@ int main()
|
||||||
|
|
||||||
auto engine = TemplatingEngine(data_loc);
|
auto engine = TemplatingEngine(data_loc);
|
||||||
engine.loadTemplateFiles();
|
engine.loadTemplateFiles();
|
||||||
engine.processTemplate("index");
|
const auto content = engine.processTemplate("index");
|
||||||
engine.processTemplate("base");
|
|
||||||
|
|
||||||
|
|
||||||
|
File outfile("index.html");
|
||||||
|
outfile.WriteText(content);
|
||||||
}
|
}
|
Loading…
Reference in a new issue