MQTTSuite
Loading...
Searching...
No Matches
inja::Renderer Class Reference

Class for rendering a Template with data. More...

#include <inja.hpp>

Inheritance diagram for inja::Renderer:
Collaboration diagram for inja::Renderer:

Public Member Functions

 Renderer (const RenderConfig &config, const TemplateStorage &template_storage, const FunctionStorage &function_storage)
void render_to (std::ostream &os, const Template &tmpl, const json &data, json *loop_data=nullptr)
Public Member Functions inherited from inja::NodeVisitor
virtual ~NodeVisitor ()=default

Private Types

using Op = FunctionStorage::Operation

Private Member Functions

void print_data (const std::shared_ptr< json > value)
const std::shared_ptr< jsoneval_expression_list (const ExpressionListNode &expression_list)
void throw_renderer_error (const std::string &message, const AstNode &node)
void make_result (const json &&result)
template<size_t N, size_t N_start = 0, bool throw_not_found = true>
std::array< const json *, N > get_arguments (const FunctionNode &node)
template<bool throw_not_found = true>
Arguments get_argument_vector (const FunctionNode &node)
void visit (const BlockNode &node) override
void visit (const TextNode &node) override
void visit (const ExpressionNode &) override
void visit (const LiteralNode &node) override
void visit (const DataNode &node) override
void visit (const FunctionNode &node) override
void visit (const ExpressionListNode &node) override
void visit (const StatementNode &) override
void visit (const ForStatementNode &) override
void visit (const ForArrayStatementNode &node) override
void visit (const ForObjectStatementNode &node) override
void visit (const IfStatementNode &node) override
void visit (const IncludeStatementNode &node) override
void visit (const ExtendsStatementNode &node) override
void visit (const BlockStatementNode &node) override
void visit (const SetStatementNode &node) override

Static Private Member Functions

static bool truthy (const json *data)

Private Attributes

const RenderConfig config
const TemplateStoragetemplate_storage
const FunctionStoragefunction_storage
const Templatecurrent_template
size_t current_level {0}
std::vector< const Template * > template_stack
std::vector< const BlockStatementNode * > block_statement_stack
const jsondata_input
std::ostream * output_stream
json additional_data
jsoncurrent_loop_data = &additional_data["loop"]
std::vector< std::shared_ptr< json > > data_tmp_stack
std::stack< const json * > data_eval_stack
std::stack< const DataNode * > not_found_stack
bool break_rendering {false}

Detailed Description

Class for rendering a Template with data.

Definition at line 2205 of file inja.hpp.

Member Typedef Documentation

◆ Op

Definition at line 2206 of file inja.hpp.

Constructor & Destructor Documentation

◆ Renderer()

inja::Renderer::Renderer ( const RenderConfig & config,
const TemplateStorage & template_storage,
const FunctionStorage & function_storage )
inline

Definition at line 2816 of file inja.hpp.

2817 : config(config)
2820 }
const RenderConfig config
Definition inja.hpp:2208
const FunctionStorage & function_storage
Definition inja.hpp:2210
const TemplateStorage & template_storage
Definition inja.hpp:2209

References config, function_storage, and template_storage.

Member Function Documentation

◆ eval_expression_list()

const std::shared_ptr< json > inja::Renderer::eval_expression_list ( const ExpressionListNode & expression_list)
inlineprivate

Definition at line 2253 of file inja.hpp.

2253 {
2254 if (!expression_list.root) {
2255 throw_renderer_error("empty expression", expression_list);
2256 }
2257
2258 expression_list.root->accept(*this);
2259
2260 if (data_eval_stack.empty()) {
2261 throw_renderer_error("empty expression", expression_list);
2262 } else if (data_eval_stack.size() != 1) {
2263 throw_renderer_error("malformed expression", expression_list);
2264 }
2265
2266 const auto result = data_eval_stack.top();
2267 data_eval_stack.pop();
2268
2269 if (!result) {
2270 if (not_found_stack.empty()) {
2271 throw_renderer_error("expression could not be evaluated", expression_list);
2272 }
2273
2274 auto node = not_found_stack.top();
2275 not_found_stack.pop();
2276
2277 throw_renderer_error("variable '" + static_cast<std::string>(node->name) + "' not found", *node);
2278 }
2279 return std::make_shared<json>(*result);
2280 }
void throw_renderer_error(const std::string &message, const AstNode &node)
Definition inja.hpp:2282
std::stack< const json * > data_eval_stack
Definition inja.hpp:2224
std::stack< const DataNode * > not_found_stack
Definition inja.hpp:2225

References inja::ExpressionNode::accept(), data_eval_stack, inja::DataNode::name, not_found_stack, inja::ExpressionListNode::root, and throw_renderer_error().

Referenced by visit(), visit(), visit(), visit(), and visit().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_argument_vector()

template<bool throw_not_found = true>
Arguments inja::Renderer::get_argument_vector ( const FunctionNode & node)
inlineprivate

Definition at line 2329 of file inja.hpp.

2329 {
2330 const size_t N = node.arguments.size();
2331 for (auto a : node.arguments) {
2332 a->accept(*this);
2333 }
2334
2335 if (data_eval_stack.size() < N) {
2336 throw_renderer_error("function needs " + std::to_string(N) + " variables, but has only found " +
2337 std::to_string(data_eval_stack.size()),
2338 node);
2339 }
2340
2341 Arguments result{N};
2342 for (size_t i = 0; i < N; i += 1) {
2343 result[N - i - 1] = data_eval_stack.top();
2344 data_eval_stack.pop();
2345
2346 if (!result[N - i - 1]) {
2347 const auto data_node = not_found_stack.top();
2348 not_found_stack.pop();
2349
2350 if (throw_not_found) {
2351 throw_renderer_error("variable '" + static_cast<std::string>(data_node->name) + "' not found", *data_node);
2352 }
2353 }
2354 }
2355 return result;
2356 }
std::vector< const nlohmann::json * > Arguments

References inja::ExpressionNode::accept(), inja::FunctionNode::arguments, data_eval_stack, inja::DataNode::name, not_found_stack, and throw_renderer_error().

Here is the call graph for this function:

◆ get_arguments()

template<size_t N, size_t N_start = 0, bool throw_not_found = true>
std::array< const json *, N > inja::Renderer::get_arguments ( const FunctionNode & node)
inlineprivate

Definition at line 2294 of file inja.hpp.

2294 {
2295 if (node.arguments.size() < N_start + N) {
2296 throw_renderer_error("function needs " + std::to_string(N_start + N) + " variables, but has only found " +
2297 std::to_string(node.arguments.size()),
2298 node);
2299 }
2300
2301 for (size_t i = N_start; i < N_start + N; i += 1) {
2302 node.arguments[i]->accept(*this);
2303 }
2304
2305 if (data_eval_stack.size() < N) {
2306 throw_renderer_error("function needs " + std::to_string(N) + " variables, but has only found " +
2307 std::to_string(data_eval_stack.size()),
2308 node);
2309 }
2310
2311 std::array<const json*, N> result;
2312 for (size_t i = 0; i < N; i += 1) {
2313 result[N - i - 1] = data_eval_stack.top();
2314 data_eval_stack.pop();
2315
2316 if (!result[N - i - 1]) {
2317 const auto data_node = not_found_stack.top();
2318 not_found_stack.pop();
2319
2320 if (throw_not_found) {
2321 throw_renderer_error("variable '" + static_cast<std::string>(data_node->name) + "' not found", *data_node);
2322 }
2323 }
2324 }
2325 return result;
2326 }

References inja::ExpressionNode::accept(), inja::FunctionNode::arguments, data_eval_stack, inja::DataNode::name, not_found_stack, and throw_renderer_error().

Here is the call graph for this function:

◆ make_result()

void inja::Renderer::make_result ( const json && result)
inlineprivate

Definition at line 2287 of file inja.hpp.

2287 {
2288 auto result_ptr = std::make_shared<json>(result);
2289 data_tmp_stack.push_back(result_ptr);
2290 data_eval_stack.push(result_ptr.get());
2291 }
std::vector< std::shared_ptr< json > > data_tmp_stack
Definition inja.hpp:2223

References data_eval_stack, and data_tmp_stack.

◆ print_data()

void inja::Renderer::print_data ( const std::shared_ptr< json > value)
inlineprivate

Definition at line 2240 of file inja.hpp.

2240 {
2241 if (value->is_string()) {
2242 *output_stream << value->get_ref<const json::string_t&>();
2243 } else if (value->is_number_unsigned()) {
2244 *output_stream << value->get<const json::number_unsigned_t>();
2245 } else if (value->is_number_integer()) {
2246 *output_stream << value->get<const json::number_integer_t>();
2247 } else if (value->is_null()) {
2248 } else {
2249 *output_stream << value->dump();
2250 }
2251 }
std::ostream * output_stream
Definition inja.hpp:2218

References output_stream.

◆ render_to()

void inja::Renderer::render_to ( std::ostream & os,
const Template & tmpl,
const json & data,
json * loop_data = nullptr )
inline

Definition at line 2822 of file inja.hpp.

2822 {
2823 output_stream = &os;
2824 current_template = &tmpl;
2825 data_input = &data;
2826 if (loop_data) {
2827 additional_data = *loop_data;
2829 }
2830
2831 template_stack.emplace_back(current_template);
2832 current_template->root.accept(*this);
2833
2834 data_tmp_stack.clear();
2835 }
const json * data_input
Definition inja.hpp:2217
json additional_data
Definition inja.hpp:2220
const Template * current_template
Definition inja.hpp:2212
std::vector< const Template * > template_stack
Definition inja.hpp:2214
json * current_loop_data
Definition inja.hpp:2221

References inja::BlockNode::accept(), additional_data, current_loop_data, current_template, data_input, data_tmp_stack, output_stream, inja::Template::root, and template_stack.

Here is the call graph for this function:

◆ throw_renderer_error()

void inja::Renderer::throw_renderer_error ( const std::string & message,
const AstNode & node )
inlineprivate

Definition at line 2282 of file inja.hpp.

2282 {
2283 SourceLocation loc = get_source_location(current_template->content, node.pos);
2284 INJA_THROW(RenderError(message, loc));
2285 }
#define INJA_THROW(exception)
Definition inja.hpp:45
SourceLocation get_source_location(std::string_view content, size_t pos)
Definition inja.hpp:330

References inja::Template::content, current_template, inja::get_source_location(), inja::AstNode::pos, and inja::RenderError::RenderError().

Referenced by eval_expression_list(), get_argument_vector(), get_arguments(), visit(), visit(), visit(), visit(), and visit().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ truthy()

bool inja::Renderer::truthy ( const json * data)
inlinestaticprivate

Definition at line 2229 of file inja.hpp.

2229 {
2230 if (data->is_boolean()) {
2231 return data->get<bool>();
2232 } else if (data->is_number()) {
2233 return (*data != 0);
2234 } else if (data->is_null()) {
2235 return false;
2236 }
2237 return !data->empty();
2238 }

◆ visit() [1/16]

void inja::Renderer::visit ( const BlockNode & node)
inlineoverrideprivatevirtual

Implements inja::NodeVisitor.

Definition at line 2358 of file inja.hpp.

2358 {
2359 for (auto& n : node.nodes) {
2360 n->accept(*this);
2361
2362 if (break_rendering) {
2363 break;
2364 }
2365 }
2366 }
bool break_rendering
Definition inja.hpp:2227

References inja::AstNode::accept(), break_rendering, and inja::BlockNode::nodes.

Here is the call graph for this function:

◆ visit() [2/16]

void inja::Renderer::visit ( const BlockStatementNode & node)
inlineoverrideprivatevirtual

Implements inja::NodeVisitor.

Definition at line 2794 of file inja.hpp.

2794 {
2795 const size_t old_level = current_level;
2796 current_level = 0;
2798 const auto block_it = current_template->block_storage.find(node.name);
2799 if (block_it != current_template->block_storage.end()) {
2800 block_statement_stack.emplace_back(&node);
2801 block_it->second->block.accept(*this);
2802 block_statement_stack.pop_back();
2803 }
2804 current_level = old_level;
2806 }
size_t current_level
Definition inja.hpp:2213
std::vector< const BlockStatementNode * > block_statement_stack
Definition inja.hpp:2215

References inja::BlockNode::accept(), inja::BlockStatementNode::block, block_statement_stack, inja::Template::block_storage, current_level, current_template, inja::BlockStatementNode::name, and template_stack.

Here is the call graph for this function:

◆ visit() [3/16]

void inja::Renderer::visit ( const DataNode & node)
inlineoverrideprivatevirtual

Implements inja::NodeVisitor.

Definition at line 2379 of file inja.hpp.

2379 {
2380 if (additional_data.contains(node.ptr)) {
2381 data_eval_stack.push(&(additional_data[node.ptr]));
2382 } else if (data_input->contains(node.ptr)) {
2383 data_eval_stack.push(&(*data_input)[node.ptr]);
2384 } else {
2385 // Try to evaluate as a no-argument callback
2386 const auto function_data = function_storage.find_function(node.name, 0);
2387 if (function_data.operation == FunctionStorage::Operation::Callback) {
2388 Arguments empty_args{};
2389 const auto value = std::make_shared<json>(function_data.callback(empty_args));
2390 data_tmp_stack.push_back(value);
2391 data_eval_stack.push(value.get());
2392 } else {
2393 data_eval_stack.push(nullptr);
2394 not_found_stack.emplace(&node);
2395 }
2396 }
2397 }

References additional_data, inja::FunctionStorage::Callback, inja::FunctionStorage::FunctionData::callback, data_eval_stack, data_input, data_tmp_stack, inja::FunctionStorage::find_function(), function_storage, inja::DataNode::name, not_found_stack, inja::FunctionStorage::FunctionData::operation, and inja::DataNode::ptr.

Here is the call graph for this function:

◆ visit() [4/16]

void inja::Renderer::visit ( const ExpressionListNode & node)
inlineoverrideprivatevirtual

Implements inja::NodeVisitor.

Definition at line 2676 of file inja.hpp.

2676 {
2678 }
const std::shared_ptr< json > eval_expression_list(const ExpressionListNode &expression_list)
Definition inja.hpp:2253
void print_data(const std::shared_ptr< json > value)
Definition inja.hpp:2240

References eval_expression_list().

Here is the call graph for this function:

◆ visit() [5/16]

void inja::Renderer::visit ( const ExpressionNode & )
inlineoverrideprivatevirtual

Implements inja::NodeVisitor.

Definition at line 2372 of file inja.hpp.

2372 {
2373 }

◆ visit() [6/16]

void inja::Renderer::visit ( const ExtendsStatementNode & node)
inlineoverrideprivatevirtual

Implements inja::NodeVisitor.

Definition at line 2783 of file inja.hpp.

2783 {
2784 const auto included_template_it = template_storage.find(node.file);
2785 if (included_template_it != template_storage.end()) {
2786 const Template* parent_template = &included_template_it->second;
2787 render_to(*output_stream, *parent_template, *data_input, &additional_data);
2788 break_rendering = true;
2789 } else if (config.throw_at_missing_includes) {
2790 throw_renderer_error("extends '" + node.file + "' not found", node);
2791 }
2792 }
void render_to(std::ostream &os, const Template &tmpl, const json &data, json *loop_data=nullptr)
Definition inja.hpp:2822

References additional_data, break_rendering, config, data_input, inja::ExtendsStatementNode::file, output_stream, template_storage, inja::RenderConfig::throw_at_missing_includes, and throw_renderer_error().

Here is the call graph for this function:

◆ visit() [7/16]

void inja::Renderer::visit ( const ForArrayStatementNode & node)
inlineoverrideprivatevirtual

Implements inja::NodeVisitor.

Definition at line 2686 of file inja.hpp.

2686 {
2687 const auto result = eval_expression_list(node.condition);
2688 if (!result->is_array()) {
2689 throw_renderer_error("object must be an array", node);
2690 }
2691
2692 if (!current_loop_data->empty()) {
2693 auto tmp = *current_loop_data; // Because of clang-3
2694 (*current_loop_data)["parent"] = std::move(tmp);
2695 }
2696
2697 size_t index = 0;
2698 (*current_loop_data)["is_first"] = true;
2699 (*current_loop_data)["is_last"] = (result->size() <= 1);
2700 for (auto it = result->begin(); it != result->end(); ++it) {
2701 additional_data[static_cast<std::string>(node.value)] = *it;
2702
2703 (*current_loop_data)["index"] = index;
2704 (*current_loop_data)["index1"] = index + 1;
2705 if (index == 1) {
2706 (*current_loop_data)["is_first"] = false;
2707 }
2708 if (index == result->size() - 1) {
2709 (*current_loop_data)["is_last"] = true;
2710 }
2711
2712 node.body.accept(*this);
2713 ++index;
2714 }
2715
2716 additional_data[static_cast<std::string>(node.value)].clear();
2717 if (!(*current_loop_data)["parent"].empty()) {
2718 const auto tmp = (*current_loop_data)["parent"];
2719 *current_loop_data = std::move(tmp);
2720 } else {
2722 }
2723 }

References inja::BlockNode::accept(), additional_data, inja::ForStatementNode::body, inja::ForStatementNode::condition, current_loop_data, eval_expression_list(), throw_renderer_error(), and inja::ForArrayStatementNode::value.

Here is the call graph for this function:

◆ visit() [8/16]

void inja::Renderer::visit ( const ForObjectStatementNode & node)
inlineoverrideprivatevirtual

Implements inja::NodeVisitor.

Definition at line 2725 of file inja.hpp.

2725 {
2726 const auto result = eval_expression_list(node.condition);
2727 if (!result->is_object()) {
2728 throw_renderer_error("object must be an object", node);
2729 }
2730
2731 if (!current_loop_data->empty()) {
2732 (*current_loop_data)["parent"] = std::move(*current_loop_data);
2733 }
2734
2735 size_t index = 0;
2736 (*current_loop_data)["is_first"] = true;
2737 (*current_loop_data)["is_last"] = (result->size() <= 1);
2738 for (auto it = result->begin(); it != result->end(); ++it) {
2739 additional_data[static_cast<std::string>(node.key)] = it.key();
2740 additional_data[static_cast<std::string>(node.value)] = it.value();
2741
2742 (*current_loop_data)["index"] = index;
2743 (*current_loop_data)["index1"] = index + 1;
2744 if (index == 1) {
2745 (*current_loop_data)["is_first"] = false;
2746 }
2747 if (index == result->size() - 1) {
2748 (*current_loop_data)["is_last"] = true;
2749 }
2750
2751 node.body.accept(*this);
2752 ++index;
2753 }
2754
2755 additional_data[static_cast<std::string>(node.key)].clear();
2756 additional_data[static_cast<std::string>(node.value)].clear();
2757 if (!(*current_loop_data)["parent"].empty()) {
2758 *current_loop_data = std::move((*current_loop_data)["parent"]);
2759 } else {
2761 }
2762 }

References inja::BlockNode::accept(), additional_data, inja::ForStatementNode::body, inja::ForStatementNode::condition, current_loop_data, eval_expression_list(), inja::ForObjectStatementNode::key, throw_renderer_error(), and inja::ForObjectStatementNode::value.

Here is the call graph for this function:

◆ visit() [9/16]

void inja::Renderer::visit ( const ForStatementNode & )
inlineoverrideprivatevirtual

Implements inja::NodeVisitor.

Definition at line 2683 of file inja.hpp.

2683 {
2684 }

◆ visit() [10/16]

void inja::Renderer::visit ( const FunctionNode & node)
inlineoverrideprivatevirtual

Implements inja::NodeVisitor.

Definition at line 2399 of file inja.hpp.

2399 {
2400 switch (node.operation) {
2401 case Op::Not: {
2402 const auto args = get_arguments<1>(node);
2403 make_result(!truthy(args[0]));
2404 } break;
2405 case Op::And: {
2407 } break;
2408 case Op::Or: {
2410 } break;
2411 case Op::In: {
2412 const auto args = get_arguments<2>(node);
2413 make_result(std::find(args[1]->begin(), args[1]->end(), *args[0]) != args[1]->end());
2414 } break;
2415 case Op::Equal: {
2416 const auto args = get_arguments<2>(node);
2417 make_result(*args[0] == *args[1]);
2418 } break;
2419 case Op::NotEqual: {
2420 const auto args = get_arguments<2>(node);
2421 make_result(*args[0] != *args[1]);
2422 } break;
2423 case Op::Greater: {
2424 const auto args = get_arguments<2>(node);
2425 make_result(*args[0] > *args[1]);
2426 } break;
2427 case Op::GreaterEqual: {
2428 const auto args = get_arguments<2>(node);
2429 make_result(*args[0] >= *args[1]);
2430 } break;
2431 case Op::Less: {
2432 const auto args = get_arguments<2>(node);
2433 make_result(*args[0] < *args[1]);
2434 } break;
2435 case Op::LessEqual: {
2436 const auto args = get_arguments<2>(node);
2437 make_result(*args[0] <= *args[1]);
2438 } break;
2439 case Op::Add: {
2440 const auto args = get_arguments<2>(node);
2441 if (args[0]->is_string() && args[1]->is_string()) {
2442 make_result(args[0]->get_ref<const json::string_t&>() + args[1]->get_ref<const json::string_t&>());
2443 } else if (args[0]->is_number_integer() && args[1]->is_number_integer()) {
2444 make_result(args[0]->get<const json::number_integer_t>() + args[1]->get<const json::number_integer_t>());
2445 } else {
2446 make_result(args[0]->get<const json::number_float_t>() + args[1]->get<const json::number_float_t>());
2447 }
2448 } break;
2449 case Op::Subtract: {
2450 const auto args = get_arguments<2>(node);
2451 if (args[0]->is_number_integer() && args[1]->is_number_integer()) {
2452 make_result(args[0]->get<const json::number_integer_t>() - args[1]->get<const json::number_integer_t>());
2453 } else {
2454 make_result(args[0]->get<const json::number_float_t>() - args[1]->get<const json::number_float_t>());
2455 }
2456 } break;
2457 case Op::Multiplication: {
2458 const auto args = get_arguments<2>(node);
2459 if (args[0]->is_number_integer() && args[1]->is_number_integer()) {
2460 make_result(args[0]->get<const json::number_integer_t>() * args[1]->get<const json::number_integer_t>());
2461 } else {
2462 make_result(args[0]->get<const json::number_float_t>() * args[1]->get<const json::number_float_t>());
2463 }
2464 } break;
2465 case Op::Division: {
2466 const auto args = get_arguments<2>(node);
2467 if (args[1]->get<const json::number_float_t>() == 0) {
2468 throw_renderer_error("division by zero", node);
2469 }
2470 make_result(args[0]->get<const json::number_float_t>() / args[1]->get<const json::number_float_t>());
2471 } break;
2472 case Op::Power: {
2473 const auto args = get_arguments<2>(node);
2474 if (args[0]->is_number_integer() && args[1]->get<const json::number_integer_t>() >= 0) {
2475 const auto result = static_cast<json::number_integer_t>(
2476 std::pow(args[0]->get<const json::number_integer_t>(), args[1]->get<const json::number_integer_t>()));
2477 make_result(result);
2478 } else {
2479 const auto result =
2480 std::pow(args[0]->get<const json::number_float_t>(), args[1]->get<const json::number_integer_t>());
2481 make_result(result);
2482 }
2483 } break;
2484 case Op::Modulo: {
2485 const auto args = get_arguments<2>(node);
2486 make_result(args[0]->get<const json::number_integer_t>() % args[1]->get<const json::number_integer_t>());
2487 } break;
2488 case Op::AtId: {
2489 const auto container = get_arguments<1, 0, false>(node)[0];
2490 node.arguments[1]->accept(*this);
2491 if (not_found_stack.empty()) {
2492 throw_renderer_error("could not find element with given name", node);
2493 }
2494 const auto id_node = not_found_stack.top();
2495 not_found_stack.pop();
2496 data_eval_stack.pop();
2497 data_eval_stack.push(&container->at(id_node->name));
2498 } break;
2499 case Op::At: {
2500 const auto args = get_arguments<2>(node);
2501 if (args[0]->is_object()) {
2502 data_eval_stack.push(&args[0]->at(args[1]->get<std::string>()));
2503 } else {
2504 data_eval_stack.push(&args[0]->at(args[1]->get<std::stack<const json*>::size_type>()));
2505 }
2506 } break;
2507 case Op::Default: {
2508 const auto test_arg = get_arguments<1, 0, false>(node)[0];
2509 data_eval_stack.push(test_arg ? test_arg : get_arguments<1, 1>(node)[0]);
2510 } break;
2511 case Op::DivisibleBy: {
2512 const auto args = get_arguments<2>(node);
2513 const auto divisor = args[1]->get<const json::number_integer_t>();
2514 make_result((divisor != 0) && (args[0]->get<const json::number_integer_t>() % divisor == 0));
2515 } break;
2516 case Op::Even: {
2517 make_result(get_arguments<1>(node)[0]->get<const json::number_integer_t>() % 2 == 0);
2518 } break;
2519 case Op::Exists: {
2520 auto&& name = get_arguments<1>(node)[0]->get_ref<const json::string_t&>();
2521 make_result(data_input->contains(json::json_pointer(DataNode::convert_dot_to_ptr(name))));
2522 } break;
2523 case Op::ExistsInObject: {
2524 const auto args = get_arguments<2>(node);
2525 auto&& name = args[1]->get_ref<const json::string_t&>();
2526 make_result(args[0]->find(name) != args[0]->end());
2527 } break;
2528 case Op::First: {
2529 const auto result = &get_arguments<1>(node)[0]->front();
2530 data_eval_stack.push(result);
2531 } break;
2532 case Op::Float: {
2533 make_result(std::stod(get_arguments<1>(node)[0]->get_ref<const json::string_t&>()));
2534 } break;
2535 case Op::Int: {
2536 make_result(std::stoi(get_arguments<1>(node)[0]->get_ref<const json::string_t&>()));
2537 } break;
2538 case Op::Last: {
2539 const auto result = &get_arguments<1>(node)[0]->back();
2540 data_eval_stack.push(result);
2541 } break;
2542 case Op::Length: {
2543 const auto val = get_arguments<1>(node)[0];
2544 if (val->is_string()) {
2545 make_result(val->get_ref<const json::string_t&>().length());
2546 } else {
2547 make_result(val->size());
2548 }
2549 } break;
2550 case Op::Lower: {
2551 auto result = get_arguments<1>(node)[0]->get<json::string_t>();
2552 std::transform(result.begin(), result.end(), result.begin(), [](char c) {
2553 return static_cast<char>(::tolower(c));
2554 });
2555 make_result(std::move(result));
2556 } break;
2557 case Op::Max: {
2558 const auto args = get_arguments<1>(node);
2559 const auto result = std::max_element(args[0]->begin(), args[0]->end());
2560 data_eval_stack.push(&(*result));
2561 } break;
2562 case Op::Min: {
2563 const auto args = get_arguments<1>(node);
2564 const auto result = std::min_element(args[0]->begin(), args[0]->end());
2565 data_eval_stack.push(&(*result));
2566 } break;
2567 case Op::Odd: {
2568 make_result(get_arguments<1>(node)[0]->get<const json::number_integer_t>() % 2 != 0);
2569 } break;
2570 case Op::Range: {
2571 std::vector<int> result(get_arguments<1>(node)[0]->get<std::vector<int>::size_type>());
2572 std::iota(result.begin(), result.end(), 0);
2573 make_result(std::move(result));
2574 } break;
2575 case Op::Round: {
2576 const auto args = get_arguments<2>(node);
2577 const int precision = args[1]->get<int>();
2578 const double result =
2579 std::round(args[0]->get<const json::number_float_t>() * std::pow(10.0, precision)) / std::pow(10.0, precision);
2580 if (precision == 0) {
2581 make_result(int(result));
2582 } else {
2583 make_result(result);
2584 }
2585 } break;
2586 case Op::Sort: {
2587 auto result_ptr = std::make_shared<json>(get_arguments<1>(node)[0]->get<std::vector<json>>());
2588 std::sort(result_ptr->begin(), result_ptr->end());
2589 data_tmp_stack.push_back(result_ptr);
2590 data_eval_stack.push(result_ptr.get());
2591 } break;
2592 case Op::Upper: {
2593 auto result = get_arguments<1>(node)[0]->get<json::string_t>();
2594 std::transform(result.begin(), result.end(), result.begin(), [](char c) {
2595 return static_cast<char>(::toupper(c));
2596 });
2597 make_result(std::move(result));
2598 } break;
2599 case Op::IsBoolean: {
2600 make_result(get_arguments<1>(node)[0]->is_boolean());
2601 } break;
2602 case Op::IsNumber: {
2603 make_result(get_arguments<1>(node)[0]->is_number());
2604 } break;
2605 case Op::IsInteger: {
2606 make_result(get_arguments<1>(node)[0]->is_number_integer());
2607 } break;
2608 case Op::IsFloat: {
2609 make_result(get_arguments<1>(node)[0]->is_number_float());
2610 } break;
2611 case Op::IsObject: {
2612 make_result(get_arguments<1>(node)[0]->is_object());
2613 } break;
2614 case Op::IsArray: {
2615 make_result(get_arguments<1>(node)[0]->is_array());
2616 } break;
2617 case Op::IsString: {
2618 make_result(get_arguments<1>(node)[0]->is_string());
2619 } break;
2620 case Op::Callback: {
2621 auto args = get_argument_vector(node);
2622 make_result(node.callback(args));
2623 } break;
2624 case Op::Super: {
2625 const auto args = get_argument_vector(node);
2626 const size_t old_level = current_level;
2627 const size_t level_diff = (args.size() == 1) ? args[0]->get<size_t>() : 1;
2628 const size_t level = current_level + level_diff;
2629
2630 if (block_statement_stack.empty()) {
2631 throw_renderer_error("super() call is not within a block", node);
2632 }
2633
2634 if (level < 1 || level > template_stack.size() - 1) {
2635 throw_renderer_error("level of super() call does not match parent templates (between 1 and " +
2636 std::to_string(template_stack.size() - 1) + ")",
2637 node);
2638 }
2639
2640 const auto current_block_statement = block_statement_stack.back();
2641 const Template* new_template = template_stack.at(level);
2642 const Template* old_template = current_template;
2643 const auto block_it = new_template->block_storage.find(current_block_statement->name);
2644 if (block_it != new_template->block_storage.end()) {
2645 current_template = new_template;
2646 current_level = level;
2647 block_it->second->block.accept(*this);
2648 current_level = old_level;
2649 current_template = old_template;
2650 } else {
2651 throw_renderer_error("could not find block with name '" + current_block_statement->name + "'", node);
2652 }
2653 make_result(nullptr);
2654 } break;
2655 case Op::Join: {
2656 const auto args = get_arguments<2>(node);
2657 const auto separator = args[1]->get<json::string_t>();
2658 std::ostringstream os;
2659 std::string sep;
2660 for (const auto& value : *args[0]) {
2661 os << sep;
2662 if (value.is_string()) {
2663 os << value.get<std::string>(); // otherwise the value is surrounded with ""
2664 } else {
2665 os << value.dump();
2666 }
2667 sep = separator;
2668 }
2669 make_result(os.str());
2670 } break;
2671 case Op::None:
2672 break;
2673 }
2674 }
static std::string convert_dot_to_ptr(std::string_view ptr_name)
Definition inja.hpp:486
std::array< const json *, N > get_arguments(const FunctionNode &node)
Definition inja.hpp:2294
Arguments get_argument_vector(const FunctionNode &node)
Definition inja.hpp:2329
static bool truthy(const json *data)
Definition inja.hpp:2229
void make_result(const json &&result)
Definition inja.hpp:2287

References inja::BlockNode::accept(), inja::ExpressionNode::accept(), inja::FunctionStorage::Add, inja::FunctionStorage::And, inja::FunctionNode::arguments, inja::FunctionStorage::At, inja::FunctionStorage::AtId, inja::BlockStatementNode::block, block_statement_stack, inja::Template::block_storage, inja::FunctionStorage::Callback, inja::FunctionNode::callback, inja::DataNode::convert_dot_to_ptr(), current_level, current_template, data_eval_stack, data_input, data_tmp_stack, inja::FunctionStorage::Default, inja::FunctionStorage::DivisibleBy, inja::FunctionStorage::Division, inja::FunctionStorage::Equal, inja::FunctionStorage::Even, inja::FunctionStorage::Exists, inja::FunctionStorage::ExistsInObject, inja::FunctionStorage::First, inja::FunctionStorage::Float, inja::FunctionStorage::Greater, inja::FunctionStorage::GreaterEqual, inja::FunctionStorage::In, inja::FunctionStorage::Int, inja::FunctionStorage::IsArray, inja::FunctionStorage::IsBoolean, inja::FunctionStorage::IsFloat, inja::FunctionStorage::IsInteger, inja::FunctionStorage::IsNumber, inja::FunctionStorage::IsObject, inja::FunctionStorage::IsString, inja::FunctionStorage::Join, inja::FunctionStorage::Last, inja::FunctionStorage::Length, inja::FunctionStorage::Less, inja::FunctionStorage::LessEqual, inja::FunctionStorage::Lower, inja::FunctionStorage::Max, inja::FunctionStorage::Min, inja::FunctionStorage::Modulo, inja::FunctionStorage::Multiplication, inja::BlockStatementNode::name, inja::DataNode::name, inja::FunctionStorage::None, inja::FunctionStorage::Not, not_found_stack, inja::FunctionStorage::NotEqual, inja::FunctionStorage::Odd, inja::FunctionNode::operation, inja::FunctionStorage::Or, inja::FunctionStorage::Power, inja::FunctionStorage::Range, inja::FunctionStorage::Round, inja::FunctionStorage::Sort, inja::FunctionStorage::Subtract, inja::FunctionStorage::Super, template_stack, throw_renderer_error(), and inja::FunctionStorage::Upper.

Here is the call graph for this function:

◆ visit() [11/16]

void inja::Renderer::visit ( const IfStatementNode & node)
inlineoverrideprivatevirtual

Implements inja::NodeVisitor.

Definition at line 2764 of file inja.hpp.

2764 {
2765 const auto result = eval_expression_list(node.condition);
2766 if (truthy(result.get())) {
2767 node.true_statement.accept(*this);
2768 } else if (node.has_false_statement) {
2769 node.false_statement.accept(*this);
2770 }
2771 }

References inja::BlockNode::accept(), inja::IfStatementNode::condition, eval_expression_list(), inja::IfStatementNode::false_statement, inja::IfStatementNode::has_false_statement, and inja::IfStatementNode::true_statement.

Here is the call graph for this function:

◆ visit() [12/16]

void inja::Renderer::visit ( const IncludeStatementNode & node)
inlineoverrideprivatevirtual

Implements inja::NodeVisitor.

Definition at line 2773 of file inja.hpp.

2773 {
2774 auto sub_renderer = Renderer(config, template_storage, function_storage);
2775 const auto included_template_it = template_storage.find(node.file);
2776 if (included_template_it != template_storage.end()) {
2777 sub_renderer.render_to(*output_stream, included_template_it->second, *data_input, &additional_data);
2778 } else if (config.throw_at_missing_includes) {
2779 throw_renderer_error("include '" + node.file + "' not found", node);
2780 }
2781 }
Renderer(const RenderConfig &config, const TemplateStorage &template_storage, const FunctionStorage &function_storage)
Definition inja.hpp:2816

References additional_data, config, data_input, inja::IncludeStatementNode::file, function_storage, output_stream, template_storage, inja::RenderConfig::throw_at_missing_includes, and throw_renderer_error().

Here is the call graph for this function:

◆ visit() [13/16]

void inja::Renderer::visit ( const LiteralNode & node)
inlineoverrideprivatevirtual

Implements inja::NodeVisitor.

Definition at line 2375 of file inja.hpp.

2375 {
2376 data_eval_stack.push(&node.value);
2377 }

References data_eval_stack, and inja::LiteralNode::value.

◆ visit() [14/16]

void inja::Renderer::visit ( const SetStatementNode & node)
inlineoverrideprivatevirtual

Implements inja::NodeVisitor.

Definition at line 2808 of file inja.hpp.

2808 {
2809 std::string ptr = node.key;
2810 replace_substring(ptr, ".", "/");
2811 ptr = "/" + ptr;
2812 additional_data[json::json_pointer(ptr)] = *eval_expression_list(node.expression);
2813 }
void replace_substring(std::string &s, const std::string &f, const std::string &t)
Definition inja.hpp:353

References additional_data, eval_expression_list(), inja::SetStatementNode::expression, inja::SetStatementNode::key, and inja::replace_substring().

Here is the call graph for this function:

◆ visit() [15/16]

void inja::Renderer::visit ( const StatementNode & )
inlineoverrideprivatevirtual

Implements inja::NodeVisitor.

Definition at line 2680 of file inja.hpp.

2680 {
2681 }

◆ visit() [16/16]

void inja::Renderer::visit ( const TextNode & node)
inlineoverrideprivatevirtual

Implements inja::NodeVisitor.

Definition at line 2368 of file inja.hpp.

2368 {
2369 output_stream->write(current_template->content.c_str() + node.pos, static_cast<std::streamsize>(node.length));
2370 }

References inja::Template::content, current_template, inja::TextNode::length, output_stream, and inja::AstNode::pos.

Member Data Documentation

◆ additional_data

json inja::Renderer::additional_data
private

Definition at line 2220 of file inja.hpp.

Referenced by render_to(), visit(), visit(), visit(), visit(), visit(), and visit().

◆ block_statement_stack

std::vector<const BlockStatementNode*> inja::Renderer::block_statement_stack
private

Definition at line 2215 of file inja.hpp.

Referenced by visit(), and visit().

◆ break_rendering

bool inja::Renderer::break_rendering {false}
private

Definition at line 2227 of file inja.hpp.

2227{false};

Referenced by visit(), and visit().

◆ config

const RenderConfig inja::Renderer::config
private

Definition at line 2208 of file inja.hpp.

Referenced by Renderer(), visit(), and visit().

◆ current_level

size_t inja::Renderer::current_level {0}
private

Definition at line 2213 of file inja.hpp.

2213{0};

Referenced by visit(), and visit().

◆ current_loop_data

json* inja::Renderer::current_loop_data = &additional_data["loop"]
private

Definition at line 2221 of file inja.hpp.

Referenced by render_to(), visit(), and visit().

◆ current_template

const Template* inja::Renderer::current_template
private

Definition at line 2212 of file inja.hpp.

Referenced by render_to(), throw_renderer_error(), visit(), visit(), and visit().

◆ data_eval_stack

std::stack<const json*> inja::Renderer::data_eval_stack
private

◆ data_input

const json* inja::Renderer::data_input
private

Definition at line 2217 of file inja.hpp.

Referenced by render_to(), visit(), visit(), visit(), and visit().

◆ data_tmp_stack

std::vector<std::shared_ptr<json> > inja::Renderer::data_tmp_stack
private

Definition at line 2223 of file inja.hpp.

Referenced by make_result(), render_to(), visit(), and visit().

◆ function_storage

const FunctionStorage& inja::Renderer::function_storage
private

Definition at line 2210 of file inja.hpp.

Referenced by Renderer(), visit(), and visit().

◆ not_found_stack

std::stack<const DataNode*> inja::Renderer::not_found_stack
private

Definition at line 2225 of file inja.hpp.

Referenced by eval_expression_list(), get_argument_vector(), get_arguments(), visit(), and visit().

◆ output_stream

std::ostream* inja::Renderer::output_stream
private

Definition at line 2218 of file inja.hpp.

Referenced by print_data(), render_to(), visit(), visit(), and visit().

◆ template_stack

std::vector<const Template*> inja::Renderer::template_stack
private

Definition at line 2214 of file inja.hpp.

Referenced by render_to(), visit(), and visit().

◆ template_storage

const TemplateStorage& inja::Renderer::template_storage
private

Definition at line 2209 of file inja.hpp.

Referenced by Renderer(), visit(), and visit().


The documentation for this class was generated from the following file: