Skip to content
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.0.1)
project(Jinja2Cpp VERSION 0.9.1)
project(Jinja2Cpp VERSION 0.9.2)

if (${CMAKE_VERSION} VERSION_GREATER "3.12")
cmake_policy(SET CMP0074 OLD)
Expand Down
5 changes: 4 additions & 1 deletion include/jinja2cpp/error_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ enum class ErrorCode
UnexpectedExprBegin,
UnexpectedExprEnd,
UnexpectedStmtBegin,
UnexpectedStmtEnd
UnexpectedStmtEnd,
TemplateNotFound,
TemplateNotParsed,
InvalidValueType,
};

struct SourceLocation
Expand Down
36 changes: 20 additions & 16 deletions include/jinja2cpp/template.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,25 @@ namespace jinja2
class ITemplateImpl;
class TemplateEnv;
template<typename CharT> class TemplateImpl;
using ParseResult = nonstd::expected<void, ErrorInfo>;
using ParseResultW = nonstd::expected<void, ErrorInfoW>;
template<typename U>
using Result = nonstd::expected<U, ErrorInfo>;
template<typename U>
using ResultW = nonstd::expected<U, ErrorInfoW>;

class Template
{
public:
Template(TemplateEnv* env = nullptr);
Template() : Template(nullptr) {}
explicit Template(TemplateEnv* env);
~Template();

ParseResult Load(const char* tpl, std::string tplName = std::string());
ParseResult Load(const std::string& str, std::string tplName = std::string());
ParseResult Load(std::istream& stream, std::string tplName = std::string());
ParseResult LoadFromFile(const std::string& fileName);
Result<void> Load(const char* tpl, std::string tplName = std::string());
Result<void> Load(const std::string& str, std::string tplName = std::string());
Result<void> Load(std::istream& stream, std::string tplName = std::string());
Result<void> LoadFromFile(const std::string& fileName);

void Render(std::ostream& os, const ValuesMap& params);
std::string RenderAsString(const ValuesMap& params);
Result<void> Render(std::ostream& os, const ValuesMap& params);
Result<std::string> RenderAsString(const ValuesMap& params);

private:
std::shared_ptr<ITemplateImpl> m_impl;
Expand All @@ -41,16 +44,17 @@ class Template
class TemplateW
{
public:
TemplateW(TemplateEnv* env = nullptr);
TemplateW() : TemplateW(nullptr) {}
explicit TemplateW(TemplateEnv* env);
~TemplateW();

ParseResultW Load(const wchar_t* tpl, std::string tplName = std::string());
ParseResultW Load(const std::wstring& str, std::string tplName = std::string());
ParseResultW Load(std::wistream& stream, std::string tplName = std::string());
ParseResultW LoadFromFile(const std::string& fileName);
ResultW<void> Load(const wchar_t* tpl, std::string tplName = std::string());
ResultW<void> Load(const std::wstring& str, std::string tplName = std::string());
ResultW<void> Load(std::wistream& stream, std::string tplName = std::string());
ResultW<void> LoadFromFile(const std::string& fileName);

void Render(std::wostream& os, const ValuesMap& params);
std::wstring RenderAsString(const ValuesMap& params);
ResultW<void> Render(std::wostream& os, const ValuesMap& params);
ResultW<std::wstring> RenderAsString(const ValuesMap& params);

private:
std::shared_ptr<ITemplateImpl> m_impl;
Expand Down
115 changes: 115 additions & 0 deletions src/ast_visitor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#ifndef AST_VISITOR_H
#define AST_VISITOR_H

namespace jinja2
{
class RendererBase;
class ExpressionEvaluatorBase;
class Statement;
class ForStatement;
class IfStatement;
class ElseBranchStatement;
class SetStatement;
class ParentBlockStatement;
class BlockStatement;
class ExtendsStatement;
class IncludeStatement;
class ImportStatement;
class MacroStatement;
class MacroCallStatement;
class ComposedRenderer;
class RawTextRenderer;
class ExpressionRenderer;

class StatementVisitor;

class VisitableStatement
{
public:
virtual void ApplyVisitor(StatementVisitor* visitor) = 0;
virtual void ApplyVisitor(StatementVisitor* visitor) const = 0;
};

#define VISITABLE_STATEMENT() \
void ApplyVisitor(StatementVisitor* visitor) override {visitor->DoVisit(this);} \
void ApplyVisitor(StatementVisitor* visitor) const override {visitor->DoVisit(this);} \

namespace detail
{
template<typename Base, typename Type>
class VisitorIfaceImpl : public Base
{
public:
using Base::DoVisit;

virtual void DoVisit(Type*) {}
virtual void DoVisit(const Type*) {}
};

template<typename Type>
class VisitorIfaceImpl<void, Type>
{
public:
virtual void DoVisit(Type*) {}
virtual void DoVisit(const Type*) {}
};

template<typename Base, typename ... Types>
struct VisitorBaseImpl;

template<typename Base, typename T, typename ... Types>
struct VisitorBaseImpl<Base, T, Types...>
{
using current_base = VisitorIfaceImpl<Base, T>;
using base_type = typename VisitorBaseImpl<current_base, Types...>::base_type;
};

template<typename Base, typename T>
struct VisitorBaseImpl<Base, T>
{
using base_type = VisitorIfaceImpl<Base, T>;
};


template<typename ... Types>
struct VisitorBase
{
using type = typename VisitorBaseImpl<void, Types ...>::base_type;
};
}

template<typename ... Types>
using VisitorBase = typename detail::VisitorBase<Types...>::type;

class StatementVisitor : public VisitorBase<
RendererBase,
Statement,
ForStatement,
IfStatement,
ElseBranchStatement,
SetStatement,
ParentBlockStatement,
BlockStatement,
ExtendsStatement,
IncludeStatement,
ImportStatement,
MacroStatement,
MacroCallStatement,
ComposedRenderer,
RawTextRenderer,
ExpressionRenderer>
{
public:
void Visit(VisitableStatement* stmt)
{
stmt->ApplyVisitor(this);
}
void Visit(const VisitableStatement* stmt)
{
stmt->ApplyVisitor(this);
}
};
}


#endif
9 changes: 9 additions & 0 deletions src/error_info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,15 @@ void RenderErrorInfo(std::basic_ostream<CharT>& os, const ErrorInfoTpl<CharT>& e
case ErrorCode::UnexpectedStmtEnd:
os << UNIVERSAL_STR("Unexpected statement block end");
break;
case ErrorCode::TemplateNotParsed:
os << UNIVERSAL_STR("Template not parsed");
break;
case ErrorCode::TemplateNotFound:
os << UNIVERSAL_STR("Template(s) not found: ") << errInfo.GetExtraParams()[0];
break;
case ErrorCode::InvalidValueType:
os << UNIVERSAL_STR("Invalid value type");
break;
}
os << std::endl << errInfo.GetLocationDescr();
}
Expand Down
2 changes: 1 addition & 1 deletion src/internal_value.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ struct OutputValueConvertor
}
result_t operator()(const Callable&) const {return result_t();}
result_t operator()(const UserCallable&) const {return result_t();}
result_t operator()(const RendererBase*) const {return result_t();}
result_t operator()(const std::shared_ptr<RendererBase>&) const {return result_t();}

template<typename T>
result_t operator()(const RecWrapper<T>& val) const
Expand Down
2 changes: 1 addition & 1 deletion src/internal_value.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ struct KeyValuePair;
class RendererBase;

class InternalValue;
using InternalValueData = nonstd::variant<EmptyValue, bool, std::string, TargetString, int64_t, double, ValueRef, ListAdapter, MapAdapter, RecursiveWrapper<KeyValuePair>, RecursiveWrapper<Callable>, RendererBase*>;
using InternalValueData = nonstd::variant<EmptyValue, bool, std::string, TargetString, int64_t, double, ValueRef, ListAdapter, MapAdapter, RecursiveWrapper<KeyValuePair>, RecursiveWrapper<Callable>, std::shared_ptr<RendererBase>>;

using InternalValueRef = ReferenceWrapper<InternalValue>;
using InternalValueMap = std::unordered_map<std::string, InternalValue>;
Expand Down
16 changes: 15 additions & 1 deletion src/lexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@ struct Token
Import,
Recursive,
Scoped,
With,
Without,
Ignore,
Missing,
Context,
From,
As,

// Template control
CommentBegin,
Expand Down Expand Up @@ -154,7 +161,14 @@ enum class Keyword
Include,
Import,
Recursive,
Scoped
Scoped,
With,
Without,
Ignore,
Missing,
Context,
From,
As,
};

struct LexerHelper
Expand Down
2 changes: 1 addition & 1 deletion src/lexertk.h
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ namespace lexertk
scan_operator();
return;
}
else if (traits::is_letter(*s_itr_))
else if (traits::is_letter(*s_itr_) || ('_' == (*s_itr_)))
{
scan_symbol();
return;
Expand Down
48 changes: 31 additions & 17 deletions src/render_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ struct IRendererCallback
virtual TargetString GetAsTargetString(const InternalValue& val) = 0;
virtual OutStream GetStreamOnString(TargetString& str) = 0;
virtual nonstd::variant<EmptyValue,
nonstd::expected<std::shared_ptr<TemplateImpl<char>>, ErrorInfo>,
nonstd::expected<std::shared_ptr<TemplateImpl<wchar_t>>, ErrorInfoW>> LoadTemplate(const std::string& fileName) const = 0;
nonstd::expected<std::shared_ptr<TemplateImpl<char>>, ErrorInfo>,
nonstd::expected<std::shared_ptr<TemplateImpl<wchar_t>>, ErrorInfoW>> LoadTemplate(const std::string& fileName) const = 0;
virtual nonstd::variant<EmptyValue,
nonstd::expected<std::shared_ptr<TemplateImpl<char>>, ErrorInfo>,
nonstd::expected<std::shared_ptr<TemplateImpl<wchar_t>>, ErrorInfoW>> LoadTemplate(const InternalValue& fileName) const = 0;
virtual void ThrowRuntimeError(ErrorCode code, ValuesList extraParams) = 0;
};

class RenderContext
Expand Down Expand Up @@ -51,25 +55,29 @@ class RenderContext

auto FindValue(const std::string& val, bool& found) const
{
for (auto p = m_scopes.rbegin(); p != m_scopes.rend(); ++ p)
auto finder = [&val, &found](auto& map) mutable
{
auto& map = *p;
auto valP = map.find(val);
if (valP != map.end())
{
auto p = map.find(val);
if (p != map.end())
found = true;

return p;
};

if (m_boundScope)
{
auto valP = finder(*m_boundScope);
if (found)
return valP;
}
}
auto valP = m_externalScope->find(val);
if (valP != m_externalScope->end())

for (auto p = m_scopes.rbegin(); p != m_scopes.rend(); ++ p)
{
found = true;
return valP;
auto valP = finder(*p);
if (found)
return valP;
}

found = false;
return m_externalScope->end();
return finder(*m_externalScope);
}

auto& GetCurrentScope() const
Expand All @@ -92,16 +100,22 @@ class RenderContext
RenderContext Clone(bool includeCurrentContext) const
{
if (!includeCurrentContext)
return RenderContext(*m_externalScope, m_rendererCallback);
return RenderContext(m_emptyScope, m_rendererCallback);

return RenderContext(*this);
}

void BindScope(InternalValueMap* scope)
{
m_boundScope = scope;
}
private:
InternalValueMap* m_currentScope;
const InternalValueMap* m_externalScope;
InternalValueMap m_emptyScope;
std::list<InternalValueMap> m_scopes;
IRendererCallback* m_rendererCallback;

const InternalValueMap* m_boundScope = nullptr;
};
} // jinja2

Expand Down
Loading