#include "helpers.h"
#include <fmt/format.h>
#include <fmt/xchar.h>
#include <jinja2cpp/error_info.h>
#include <iterator>
namespace
{
template<typename FmtCtx>
struct ValueRenderer
{
using CharT = typename FmtCtx::char_type;
FmtCtx* ctx;
explicit ValueRenderer(FmtCtx* c)
: ctx(c)
{
}
constexpr void operator()(bool val) const {
fmt::format_to(
ctx->out(),
UNIVERSAL_STR("{}").GetValue<CharT>(),
(val ? UNIVERSAL_STR("True").GetValue<CharT>(): UNIVERSAL_STR("False").GetValue<CharT>()));
}
void operator()(const jinja2::EmptyValue&) const { fmt::format_to(ctx->out(), UNIVERSAL_STR("").GetValue<CharT>()); }
template<typename CharU>
void operator()(const std::basic_string<CharU>& val) const
{
fmt::format_to(ctx->out(), UNIVERSAL_STR("{}").GetValue<CharT>(), jinja2::ConvertString<std::basic_string<CharT>>(val));
}
template<typename CharU>
void operator()(const std::basic_string_view<CharU>& val) const
{
fmt::format_to(ctx->out(), UNIVERSAL_STR("{}").GetValue<CharT>(), jinja2::ConvertString<std::basic_string<CharT>>(val));
}
void operator()(const jinja2::ValuesList& vals) const
{
fmt::format_to(ctx->out(), UNIVERSAL_STR("{{").GetValue<CharT>());
bool isFirst = true;
for (auto& val : vals)
{
if (isFirst)
isFirst = false;
else
fmt::format_to(ctx->out(), UNIVERSAL_STR(", ").GetValue<CharT>());
std::visit(ValueRenderer<FmtCtx>(ctx), val.data());
}
fmt::format_to(ctx->out(), UNIVERSAL_STR("}}").GetValue<CharT>());
}
void operator()(const jinja2::ValuesMap& vals) const
{
fmt::format_to(ctx->out(), UNIVERSAL_STR("{{").GetValue<CharT>());
bool isFirst = true;
for (auto& val : vals)
{
if (isFirst)
isFirst = false;
else
fmt::format_to(ctx->out(), UNIVERSAL_STR(", ").GetValue<CharT>());
fmt::format_to(ctx->out(), UNIVERSAL_STR("{{\"{}\",").GetValue<CharT>(), jinja2::ConvertString<std::basic_string<CharT>>(val.first));
std::visit(ValueRenderer<FmtCtx>(ctx), val.second.data());
fmt::format_to(ctx->out(), UNIVERSAL_STR("}}").GetValue<CharT>());
}
fmt::format_to(ctx->out(), UNIVERSAL_STR("}}").GetValue<CharT>());
}
template<typename T>
void operator()(const jinja2::RecWrapper<T>& val) const
{
this->operator()(const_cast<const T&>(*val));
}
void operator()(const jinja2::GenericMap& /*val*/) const {}
void operator()(const jinja2::GenericList& /*val*/) const {}
void operator()(const jinja2::UserCallable& /*val*/) const {}
template<typename T>
void operator()(const T& val) const
{
fmt::format_to(ctx->out(), UNIVERSAL_STR("{}").GetValue<CharT>(), val);
}
};
} // namespace
namespace fmt
{
template<typename CharT>
struct formatter<jinja2::Value, CharT>
{
template<typename ParseContext>
constexpr auto parse(ParseContext& ctx)
{
return ctx.begin();
}
template<typename FormatContext>
auto format(const jinja2::Value& val, FormatContext& ctx)
{
std::visit(ValueRenderer<FormatContext>(&ctx), val.data());
return fmt::format_to(ctx.out(), UNIVERSAL_STR("").GetValue<CharT>());
}
};
} // namespace fmt
namespace jinja2
{
template<typename CharT>
void RenderErrorInfo(std::basic_string<CharT>& result, const ErrorInfoTpl<CharT>& errInfo)
{
using string_t = std::basic_string<CharT>;
auto out = fmt::basic_memory_buffer<CharT>();
auto& loc = errInfo.GetErrorLocation();
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("{}:{}:{}: error: ").GetValue<CharT>(), ConvertString<string_t>(loc.fileName), loc.line, loc.col);
ErrorCode errCode = errInfo.GetCode();
switch (errCode)
{
case ErrorCode::Unspecified:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Parse error").GetValue<CharT>());
break;
case ErrorCode::UnexpectedException:
{
auto& extraParams = errInfo.GetExtraParams();
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected exception occurred during template processing. Exception: {}").GetValue<CharT>(), extraParams[0]);
break;
}
case ErrorCode::MetadataParseError:
{
auto& extraParams = errInfo.GetExtraParams();
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Error occurred during template metadata parsing. Error: {}").GetValue<CharT>(), extraParams[0]);
break;
}
case ErrorCode::YetUnsupported:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("This feature has not been supported yet").GetValue<CharT>());
break;
case ErrorCode::FileNotFound:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("File not found").GetValue<CharT>());
break;
case ErrorCode::ExpectedStringLiteral:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("String expected").GetValue<CharT>());
break;
case ErrorCode::ExpectedIdentifier:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Identifier expected").GetValue<CharT>());
break;
case ErrorCode::ExpectedSquareBracket:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("']' expected").GetValue<CharT>());
break;
case ErrorCode::ExpectedRoundBracket:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("')' expected").GetValue<CharT>());
break;
case ErrorCode::ExpectedCurlyBracket:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("'}}' expected").GetValue<CharT>());
break;
case ErrorCode::ExpectedToken:
{
auto& extraParams = errInfo.GetExtraParams();
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected token '{}'").GetValue<CharT>(), extraParams[0]);
if (extraParams.size() > 1)
{
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR(". Expected: ").GetValue<CharT>());
for (std::size_t i = 1; i < extraParams.size(); ++ i)
{
if (i != 1)
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR(", ").GetValue<CharT>());
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("\'{}\'").GetValue<CharT>(), extraParams[i]);
}
}
break;
}
case ErrorCode::ExpectedExpression:
{
auto& extraParams = errInfo.GetExtraParams();
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Expected expression, got: '{}'").GetValue<CharT>(), extraParams[0]);
break;
}
case ErrorCode::ExpectedEndOfStatement:
{
auto& extraParams = errInfo.GetExtraParams();
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Expected end of statement, got: '{}'").GetValue<CharT>(), extraParams[0]);
break;
}
case ErrorCode::ExpectedRawEnd:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Expected end of raw block").GetValue<CharT>());
break;
case ErrorCode::ExpectedMetaEnd:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Expected end of meta block").GetValue<CharT>());
break;
case ErrorCode::UnexpectedToken:
{
auto& extraParams = errInfo.GetExtraParams();
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected token: '{}'").GetValue<CharT>(), extraParams[0]);
break;
}
case ErrorCode::UnexpectedStatement:
{
auto& extraParams = errInfo.GetExtraParams();
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected statement: '{}'").GetValue<CharT>(), extraParams[0]);
break;
}
case ErrorCode::UnexpectedCommentBegin:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected comment begin").GetValue<CharT>());
break;
case ErrorCode::UnexpectedCommentEnd:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected comment end").GetValue<CharT>());
break;
case ErrorCode::UnexpectedRawBegin:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected raw block begin").GetValue<CharT>());
break;
case ErrorCode::UnexpectedRawEnd:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected raw block end").GetValue<CharT>());
break;
case ErrorCode::UnexpectedMetaBegin:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected meta block begin").GetValue<CharT>());
break;
case ErrorCode::UnexpectedMetaEnd:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected meta block end").GetValue<CharT>());
break;
case ErrorCode::UnexpectedExprBegin:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected expression block begin").GetValue<CharT>());
break;
case ErrorCode::UnexpectedExprEnd:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected expression block end").GetValue<CharT>());
break;
case ErrorCode::UnexpectedStmtBegin:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected statement block begin").GetValue<CharT>());
break;
case ErrorCode::UnexpectedStmtEnd:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected statement block end").GetValue<CharT>());
break;
case ErrorCode::TemplateNotParsed:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Template not parsed").GetValue<CharT>());
break;
case ErrorCode::TemplateNotFound:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Template(s) not found: {}").GetValue<CharT>(), errInfo.GetExtraParams()[0]);
break;
case ErrorCode::InvalidTemplateName:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Invalid template name: {}").GetValue<CharT>(), errInfo.GetExtraParams()[0]);
break;
case ErrorCode::InvalidValueType:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Invalid value type").GetValue<CharT>());
break;
case ErrorCode::ExtensionDisabled:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Extension disabled").GetValue<CharT>());
break;
case ErrorCode::TemplateEnvAbsent:
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("Template environment doesn't set").GetValue<CharT>());
break;
}
fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("\n{}").GetValue<CharT>(), errInfo.GetLocationDescr());
result = to_string(out);
}
template<>
std::string ErrorInfoTpl<char>::ToString() const
{
std::string result;
RenderErrorInfo(result, *this);
return result;
}
template<>
std::wstring ErrorInfoTpl<wchar_t>::ToString() const
{
std::wstring result;
RenderErrorInfo(result, *this);
return result;
}
std::ostream& operator << (std::ostream& os, const ErrorInfo& res)
{
os << res.ToString();
return os;
}
std::wostream& operator << (std::wostream& os, const ErrorInfoW& res)
{
os << res.ToString();
return os;
}
} // namespace jinja2