fix render error position in templates
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 @@
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 @@
// 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 @@
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 @@
if_stack.emplace_back(static_cast<decltype(if_stack)::value_type::jump_t>(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<decltype(tok.text)>("endif")) {
if (if_stack.empty()) {
throw_parser_error("endif without matching if");
@@ -389,7 +389,7 @@
// 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 @@
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<decltype(tok.text)>("for")) {
get_next_token();
@@ -442,12 +442,11 @@
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<std::string>(value_token.text);
- tmpl.nodes.back().view = value_token.text;
} else if (tok.text == static_cast<decltype(tok.text)>("endfor")) {
get_next_token();
if (loop_stack.empty()) {
@@ -457,7 +456,7 @@
// 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<decltype(tok.text)>("include")) {
@@ -483,7 +482,7 @@
}
// 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 @@
}
// 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 @@
last.op = Node::Op::Callback;
last.args = num_args;
last.str = static_cast<std::string>(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<std::string>(name);
- tmpl.nodes.back().view = name;
}
void parse_into(Template &tmpl, nonstd::string_view path) {
@@ -541,7 +539,7 @@
}
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 @@
}
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 @@
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 @@
// 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 @@
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 @@
if_stack.emplace_back(static_cast<decltype(if_stack)::value_type::jump_t>(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<decltype(tok.text)>("endif")) {
if (if_stack.empty()) {
throw_parser_error("endif without matching if");
@@ -2738,7 +2738,7 @@
// 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 @@
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<decltype(tok.text)>("for")) {
get_next_token();
@@ -2791,12 +2791,11 @@
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<std::string>(value_token.text);
- tmpl.nodes.back().view = value_token.text;
} else if (tok.text == static_cast<decltype(tok.text)>("endfor")) {
get_next_token();
if (loop_stack.empty()) {
@@ -2806,7 +2805,7 @@
// 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<decltype(tok.text)>("include")) {
@@ -2832,7 +2831,7 @@
}
// 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 @@
}
// 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 @@
last.op = Node::Op::Callback;
last.args = num_args;
last.str = static_cast<std::string>(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<std::string>(name);
- tmpl.nodes.back().view = name;
}
void parse_into(Template &tmpl, nonstd::string_view path) {
@@ -2890,7 +2888,7 @@
}
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 @@
}
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 @@
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");
}
}