Skip to content

Commit

Permalink
fix render error position in templates
Browse files Browse the repository at this point in the history
  • Loading branch information
Lars Berscheid committed Jun 30, 2020
1 parent c4d99c9 commit bb613e2
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 41 deletions.
8 changes: 4 additions & 4 deletions include/inja/node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
26 changes: 12 additions & 14 deletions include/inja/parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ class Parser {
// 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;
}
Expand Down Expand Up @@ -337,7 +337,7 @@ class Parser {
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;
}
Expand All @@ -359,7 +359,7 @@ class Parser {
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");
Expand Down Expand Up @@ -389,7 +389,7 @@ class Parser {
// 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();
Expand All @@ -408,7 +408,7 @@ class Parser {
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();
Expand Down Expand Up @@ -442,12 +442,11 @@ class Parser {

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()) {
Expand All @@ -457,7 +456,7 @@ class Parser {
// 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")) {
Expand All @@ -483,7 +482,7 @@ class Parser {
}

// 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 {
Expand All @@ -504,7 +503,7 @@ class Parser {
}

// 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) {
Expand All @@ -515,15 +514,14 @@ class Parser {
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) {
Expand All @@ -541,7 +539,7 @@ class Parser {
}
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();
Expand Down
3 changes: 1 addition & 2 deletions include/inja/renderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
37 changes: 17 additions & 20 deletions single_include/inja/inja.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -2622,7 +2622,7 @@ class Parser {
// 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;
}
Expand Down Expand Up @@ -2686,7 +2686,7 @@ class Parser {
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;
}
Expand All @@ -2708,7 +2708,7 @@ class Parser {
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");
Expand Down Expand Up @@ -2738,7 +2738,7 @@ class Parser {
// 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();
Expand All @@ -2757,7 +2757,7 @@ class Parser {
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();
Expand Down Expand Up @@ -2791,12 +2791,11 @@ class Parser {

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()) {
Expand All @@ -2806,7 +2805,7 @@ class Parser {
// 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")) {
Expand All @@ -2832,7 +2831,7 @@ class Parser {
}

// 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 {
Expand All @@ -2853,7 +2852,7 @@ class Parser {
}

// 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) {
Expand All @@ -2864,15 +2863,14 @@ class Parser {
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) {
Expand All @@ -2890,7 +2888,7 @@ class Parser {
}
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();
Expand Down Expand Up @@ -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);
}

Expand Down
2 changes: 1 addition & 1 deletion test/unit-files.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
}

0 comments on commit bb613e2

Please sign in to comment.