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