diff --git a/include/inja/node.hpp b/include/inja/node.hpp index 8a1102f..83a3ca6 100644 --- a/include/inja/node.hpp +++ b/include/inja/node.hpp @@ -119,11 +119,11 @@ struct Node { json value; std::string str; - nonstd::string_view view; + size_t pos; - explicit Node(Op op, unsigned int args = 0) : op(op), args(args), flags(0) {} - explicit Node(Op op, nonstd::string_view str, unsigned int flags) : op(op), args(0), flags(flags), str(str), view(str) {} - explicit Node(Op op, json &&value, unsigned int flags) : op(op), args(0), flags(flags), value(std::move(value)) {} + explicit Node(Op op, unsigned int args, size_t pos) : op(op), args(args), flags(0), pos(pos) {} + explicit Node(Op op, nonstd::string_view str, unsigned int flags, size_t pos) : op(op), args(0), flags(flags), str(str), pos(pos) {} + explicit Node(Op op, json &&value, unsigned int flags, size_t pos) : op(op), args(0), flags(flags), value(std::move(value)), pos(pos) {} }; } // namespace inja diff --git a/include/inja/parser.hpp b/include/inja/parser.hpp index d2cb76f..56a6484 100644 --- a/include/inja/parser.hpp +++ b/include/inja/parser.hpp @@ -273,7 +273,7 @@ public: // normal literal (json read) auto flag = config.notation == ElementNotation::Pointer ? Node::Flag::ValueLookupPointer : Node::Flag::ValueLookupDot; - tmpl.nodes.emplace_back(Node::Op::Push, tok.text, flag); + tmpl.nodes.emplace_back(Node::Op::Push, tok.text, flag, tok.text.data() - tmpl.content.c_str()); get_next_token(); return true; } @@ -337,7 +337,7 @@ public: returnJson: // bridge across all intermediate tokens nonstd::string_view json_text(json_first.data(), tok.text.data() - json_first.data() + tok.text.size()); - tmpl.nodes.emplace_back(Node::Op::Push, json::parse(json_text), Node::Flag::ValueImmediate); + tmpl.nodes.emplace_back(Node::Op::Push, json::parse(json_text), Node::Flag::ValueImmediate, tok.text.data() - tmpl.content.c_str()); get_next_token(); return true; } @@ -359,7 +359,7 @@ public: if_stack.emplace_back(static_cast(tmpl.nodes.size())); // conditional jump; destination will be filled in by else or endif - tmpl.nodes.emplace_back(Node::Op::ConditionalJump); + tmpl.nodes.emplace_back(Node::Op::ConditionalJump, 0, tok.text.data() - tmpl.content.c_str()); } else if (tok.text == static_cast("endif")) { if (if_stack.empty()) { throw_parser_error("endif without matching if"); @@ -389,7 +389,7 @@ public: // end previous block with unconditional jump to endif; destination will be // filled in by endif if_data.uncond_jumps.push_back(tmpl.nodes.size()); - tmpl.nodes.emplace_back(Node::Op::Jump); + tmpl.nodes.emplace_back(Node::Op::Jump, 0, tok.text.data() - tmpl.content.c_str()); // previous conditional jump jumps here tmpl.nodes[if_data.prev_cond_jump].args = tmpl.nodes.size(); @@ -408,7 +408,7 @@ public: if_data.prev_cond_jump = tmpl.nodes.size(); // conditional jump; destination will be filled in by else or endif - tmpl.nodes.emplace_back(Node::Op::ConditionalJump); + tmpl.nodes.emplace_back(Node::Op::ConditionalJump, 0, tok.text.data() - tmpl.content.c_str()); } } else if (tok.text == static_cast("for")) { get_next_token(); @@ -442,12 +442,11 @@ public: loop_stack.push_back(tmpl.nodes.size()); - tmpl.nodes.emplace_back(Node::Op::StartLoop); + tmpl.nodes.emplace_back(Node::Op::StartLoop, 0, tok.text.data() - tmpl.content.c_str()); if (!key_token.text.empty()) { tmpl.nodes.back().value = key_token.text; } tmpl.nodes.back().str = static_cast(value_token.text); - tmpl.nodes.back().view = value_token.text; } else if (tok.text == static_cast("endfor")) { get_next_token(); if (loop_stack.empty()) { @@ -457,7 +456,7 @@ public: // update loop with EndLoop index (for empty case) tmpl.nodes[loop_stack.back()].args = tmpl.nodes.size(); - tmpl.nodes.emplace_back(Node::Op::EndLoop); + tmpl.nodes.emplace_back(Node::Op::EndLoop, 0, tok.text.data() - tmpl.content.c_str()); tmpl.nodes.back().args = loop_stack.back() + 1; // loop body loop_stack.pop_back(); } else if (tok.text == static_cast("include")) { @@ -483,7 +482,7 @@ public: } // generate a reference node - tmpl.nodes.emplace_back(Node::Op::Include, json(pathname), Node::Flag::ValueImmediate); + tmpl.nodes.emplace_back(Node::Op::Include, json(pathname), Node::Flag::ValueImmediate, tok.text.data() - tmpl.content.c_str()); get_next_token(); } else { @@ -504,7 +503,7 @@ public: } // otherwise just add it to the end - tmpl.nodes.emplace_back(op, num_args); + tmpl.nodes.emplace_back(op, num_args, tok.text.data() - tmpl.content.c_str()); } void append_callback(Template &tmpl, nonstd::string_view name, unsigned int num_args) { @@ -515,15 +514,14 @@ public: last.op = Node::Op::Callback; last.args = num_args; last.str = static_cast(name); - last.view = name; + last.pos = name.data() - tmpl.content.c_str(); return; } } // otherwise just add it to the end - tmpl.nodes.emplace_back(Node::Op::Callback, num_args); + tmpl.nodes.emplace_back(Node::Op::Callback, num_args, tok.text.data() - tmpl.content.c_str()); tmpl.nodes.back().str = static_cast(name); - tmpl.nodes.back().view = name; } void parse_into(Template &tmpl, nonstd::string_view path) { @@ -541,7 +539,7 @@ public: } return; case Token::Kind::Text: - tmpl.nodes.emplace_back(Node::Op::PrintText, tok.text, 0u); + tmpl.nodes.emplace_back(Node::Op::PrintText, tok.text, 0u, tok.text.data() - tmpl.content.c_str()); break; case Token::Kind::StatementOpen: get_next_token(); diff --git a/include/inja/renderer.hpp b/include/inja/renderer.hpp index 44519f2..729c9bb 100644 --- a/include/inja/renderer.hpp +++ b/include/inja/renderer.hpp @@ -139,8 +139,7 @@ class Renderer { } void throw_renderer_error(const std::string &message, const Node& node) { - size_t pos = node.view.data() - current_template->content.c_str(); - SourceLocation loc = get_source_location(current_template->content, pos); + SourceLocation loc = get_source_location(current_template->content, node.pos); throw RenderError(message, loc); } diff --git a/single_include/inja/inja.hpp b/single_include/inja/inja.hpp index 43691ca..814a7f3 100644 --- a/single_include/inja/inja.hpp +++ b/single_include/inja/inja.hpp @@ -1642,11 +1642,11 @@ struct Node { json value; std::string str; - nonstd::string_view view; + size_t pos; - explicit Node(Op op, unsigned int args = 0) : op(op), args(args), flags(0) {} - explicit Node(Op op, nonstd::string_view str, unsigned int flags) : op(op), args(0), flags(flags), str(str), view(str) {} - explicit Node(Op op, json &&value, unsigned int flags) : op(op), args(0), flags(flags), value(std::move(value)) {} + explicit Node(Op op, unsigned int args, size_t pos) : op(op), args(args), flags(0), pos(pos) {} + explicit Node(Op op, nonstd::string_view str, unsigned int flags, size_t pos) : op(op), args(0), flags(flags), str(str), pos(pos) {} + explicit Node(Op op, json &&value, unsigned int flags, size_t pos) : op(op), args(0), flags(flags), value(std::move(value)), pos(pos) {} }; } // namespace inja @@ -2622,7 +2622,7 @@ public: // normal literal (json read) auto flag = config.notation == ElementNotation::Pointer ? Node::Flag::ValueLookupPointer : Node::Flag::ValueLookupDot; - tmpl.nodes.emplace_back(Node::Op::Push, tok.text, flag); + tmpl.nodes.emplace_back(Node::Op::Push, tok.text, flag, tok.text.data() - tmpl.content.c_str()); get_next_token(); return true; } @@ -2686,7 +2686,7 @@ public: returnJson: // bridge across all intermediate tokens nonstd::string_view json_text(json_first.data(), tok.text.data() - json_first.data() + tok.text.size()); - tmpl.nodes.emplace_back(Node::Op::Push, json::parse(json_text), Node::Flag::ValueImmediate); + tmpl.nodes.emplace_back(Node::Op::Push, json::parse(json_text), Node::Flag::ValueImmediate, tok.text.data() - tmpl.content.c_str()); get_next_token(); return true; } @@ -2708,7 +2708,7 @@ public: if_stack.emplace_back(static_cast(tmpl.nodes.size())); // conditional jump; destination will be filled in by else or endif - tmpl.nodes.emplace_back(Node::Op::ConditionalJump); + tmpl.nodes.emplace_back(Node::Op::ConditionalJump, 0, tok.text.data() - tmpl.content.c_str()); } else if (tok.text == static_cast("endif")) { if (if_stack.empty()) { throw_parser_error("endif without matching if"); @@ -2738,7 +2738,7 @@ public: // end previous block with unconditional jump to endif; destination will be // filled in by endif if_data.uncond_jumps.push_back(tmpl.nodes.size()); - tmpl.nodes.emplace_back(Node::Op::Jump); + tmpl.nodes.emplace_back(Node::Op::Jump, 0, tok.text.data() - tmpl.content.c_str()); // previous conditional jump jumps here tmpl.nodes[if_data.prev_cond_jump].args = tmpl.nodes.size(); @@ -2757,7 +2757,7 @@ public: if_data.prev_cond_jump = tmpl.nodes.size(); // conditional jump; destination will be filled in by else or endif - tmpl.nodes.emplace_back(Node::Op::ConditionalJump); + tmpl.nodes.emplace_back(Node::Op::ConditionalJump, 0, tok.text.data() - tmpl.content.c_str()); } } else if (tok.text == static_cast("for")) { get_next_token(); @@ -2791,12 +2791,11 @@ public: loop_stack.push_back(tmpl.nodes.size()); - tmpl.nodes.emplace_back(Node::Op::StartLoop); + tmpl.nodes.emplace_back(Node::Op::StartLoop, 0, tok.text.data() - tmpl.content.c_str()); if (!key_token.text.empty()) { tmpl.nodes.back().value = key_token.text; } tmpl.nodes.back().str = static_cast(value_token.text); - tmpl.nodes.back().view = value_token.text; } else if (tok.text == static_cast("endfor")) { get_next_token(); if (loop_stack.empty()) { @@ -2806,7 +2805,7 @@ public: // update loop with EndLoop index (for empty case) tmpl.nodes[loop_stack.back()].args = tmpl.nodes.size(); - tmpl.nodes.emplace_back(Node::Op::EndLoop); + tmpl.nodes.emplace_back(Node::Op::EndLoop, 0, tok.text.data() - tmpl.content.c_str()); tmpl.nodes.back().args = loop_stack.back() + 1; // loop body loop_stack.pop_back(); } else if (tok.text == static_cast("include")) { @@ -2832,7 +2831,7 @@ public: } // generate a reference node - tmpl.nodes.emplace_back(Node::Op::Include, json(pathname), Node::Flag::ValueImmediate); + tmpl.nodes.emplace_back(Node::Op::Include, json(pathname), Node::Flag::ValueImmediate, tok.text.data() - tmpl.content.c_str()); get_next_token(); } else { @@ -2853,7 +2852,7 @@ public: } // otherwise just add it to the end - tmpl.nodes.emplace_back(op, num_args); + tmpl.nodes.emplace_back(op, num_args, tok.text.data() - tmpl.content.c_str()); } void append_callback(Template &tmpl, nonstd::string_view name, unsigned int num_args) { @@ -2864,15 +2863,14 @@ public: last.op = Node::Op::Callback; last.args = num_args; last.str = static_cast(name); - last.view = name; + last.pos = name.data() - tmpl.content.c_str(); return; } } // otherwise just add it to the end - tmpl.nodes.emplace_back(Node::Op::Callback, num_args); + tmpl.nodes.emplace_back(Node::Op::Callback, num_args, tok.text.data() - tmpl.content.c_str()); tmpl.nodes.back().str = static_cast(name); - tmpl.nodes.back().view = name; } void parse_into(Template &tmpl, nonstd::string_view path) { @@ -2890,7 +2888,7 @@ public: } return; case Token::Kind::Text: - tmpl.nodes.emplace_back(Node::Op::PrintText, tok.text, 0u); + tmpl.nodes.emplace_back(Node::Op::PrintText, tok.text, 0u, tok.text.data() - tmpl.content.c_str()); break; case Token::Kind::StatementOpen: get_next_token(); @@ -3107,8 +3105,7 @@ class Renderer { } void throw_renderer_error(const std::string &message, const Node& node) { - size_t pos = node.view.data() - current_template->content.c_str(); - SourceLocation loc = get_source_location(current_template->content, pos); + SourceLocation loc = get_source_location(current_template->content, node.pos); throw RenderError(message, loc); } diff --git a/test/unit-files.cpp b/test/unit-files.cpp index e8fa1b0..a619933 100644 --- a/test/unit-files.cpp +++ b/test/unit-files.cpp @@ -79,6 +79,6 @@ TEST_CASE("include-without-local-files") { env.set_search_included_templates_in_files(false); SUBCASE("html") { - CHECK_THROWS_WITH(env.render_file_with_json_file("html/template.txt", "html/data.json"), "[inja.exception.render_error] (at 21:1) include '../test/data/html/header.txt' not found"); + CHECK_THROWS_WITH(env.render_file_with_json_file("html/template.txt", "html/data.json"), "[inja.exception.render_error] (at 3:14) include '../test/data/html/header.txt' not found"); } }