2015-04-12 15:35:13 +02:00
|
|
|
#include "render_context.hpp"
|
2015-04-12 17:11:49 +02:00
|
|
|
#include "utils.hpp"
|
2015-04-13 02:15:51 +02:00
|
|
|
#include "state/outside_section.hpp"
|
2015-04-09 20:41:27 +02:00
|
|
|
|
|
|
|
using namespace mstch;
|
|
|
|
|
|
|
|
const mstch::node render_context::null_node;
|
|
|
|
|
2015-04-13 02:15:51 +02:00
|
|
|
render_context::push::push(render_context& context, const mstch::object& obj):
|
|
|
|
context(context)
|
2015-04-09 20:41:27 +02:00
|
|
|
{
|
2015-04-13 02:15:51 +02:00
|
|
|
context.objects.push_front(obj);
|
|
|
|
context.push_state<state::outside_section>();
|
|
|
|
}
|
|
|
|
|
|
|
|
render_context::push::~push() {
|
|
|
|
context.objects.pop_front();
|
|
|
|
context.state.pop();
|
|
|
|
}
|
|
|
|
|
2015-04-13 16:35:12 +02:00
|
|
|
std::string render_context::push::render(const std::vector<token>& tokens) {
|
|
|
|
return context.render(tokens);
|
2015-04-09 20:41:27 +02:00
|
|
|
}
|
|
|
|
|
2015-04-10 12:56:08 +02:00
|
|
|
render_context::render_context(
|
|
|
|
const mstch::object& object,
|
2015-04-13 02:15:51 +02:00
|
|
|
const std::map<std::string,std::string>& partials):
|
|
|
|
partials{partials},
|
|
|
|
objects{object}
|
2015-04-09 20:41:27 +02:00
|
|
|
{
|
2015-04-13 02:15:51 +02:00
|
|
|
push_state<state::outside_section>();
|
|
|
|
for(auto& partial: this->partials)
|
|
|
|
partial.second = strip_whitespace(partial.second);
|
2015-04-09 20:41:27 +02:00
|
|
|
}
|
|
|
|
|
2015-04-10 12:56:08 +02:00
|
|
|
const mstch::node& render_context::find_node(
|
2015-04-11 13:05:23 +02:00
|
|
|
const std::string& token,
|
|
|
|
const std::deque<object>& current_objects)
|
2015-04-10 12:56:08 +02:00
|
|
|
{
|
2015-04-11 16:29:12 +02:00
|
|
|
if (token != "." && token.find('.') != std::string::npos)
|
2015-04-10 12:56:08 +02:00
|
|
|
return find_node(
|
|
|
|
token.substr(token.rfind('.') + 1),
|
|
|
|
{boost::get<object>(find_node(
|
|
|
|
token.substr(0, token.rfind('.')),
|
|
|
|
current_objects))});
|
2015-04-11 16:29:12 +02:00
|
|
|
else
|
2015-04-09 20:41:27 +02:00
|
|
|
for (auto& object: current_objects)
|
2015-04-11 16:29:12 +02:00
|
|
|
if (object.count(token))
|
2015-04-09 20:41:27 +02:00
|
|
|
return object.at(token);
|
2015-04-11 16:29:12 +02:00
|
|
|
return null_node;
|
2015-04-09 20:41:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const mstch::node& render_context::get_node(const std::string& token) {
|
|
|
|
return find_node(token, objects);
|
|
|
|
}
|
|
|
|
|
2015-04-13 16:35:12 +02:00
|
|
|
enum class parse_state {
|
|
|
|
start, in_del_start, in_del, in_content, in_escaped_content, in_del_end
|
|
|
|
};
|
|
|
|
|
2015-04-09 20:41:27 +02:00
|
|
|
std::string render_context::render(const std::string& t) {
|
2015-04-13 16:35:12 +02:00
|
|
|
const std::string delim_start{"{{"};
|
|
|
|
const std::string delim_end{"}}"};
|
|
|
|
std::string out;
|
|
|
|
std::string::const_iterator tok_end, tok_start = t.begin();
|
|
|
|
parse_state pstate = parse_state::start;
|
|
|
|
unsigned int delim_p = 0;
|
|
|
|
for (std::string::const_iterator it = t.begin(); it != t.end(); ++it) {
|
|
|
|
if(pstate == parse_state::start && *it == delim_start[0]) {
|
|
|
|
pstate = parse_state::in_del_start;
|
|
|
|
tok_end = it;
|
|
|
|
delim_p = 1;
|
|
|
|
} else if(pstate == parse_state::in_del_start) {
|
|
|
|
if (*it == delim_start[delim_p] && ++delim_p == delim_start.size())
|
|
|
|
pstate = parse_state::in_del;
|
|
|
|
else
|
|
|
|
pstate = parse_state::start;
|
|
|
|
} else if(pstate == parse_state::in_del) {
|
|
|
|
if (*it== '{') {
|
|
|
|
pstate = parse_state::in_escaped_content;
|
|
|
|
} else if (*it == delim_end[0]) {
|
|
|
|
pstate = parse_state::in_del_end;
|
|
|
|
delim_p = 1;
|
|
|
|
} else {
|
|
|
|
pstate = parse_state::in_content;
|
|
|
|
}
|
|
|
|
} else if(pstate == parse_state::in_escaped_content && *it == '}') {
|
|
|
|
pstate = parse_state::in_content;
|
|
|
|
} else if(pstate == parse_state::in_content && *it == delim_end[0]) {
|
|
|
|
pstate = parse_state::in_del_end;
|
|
|
|
delim_p = 1;
|
|
|
|
} else if(pstate == parse_state::in_del_end) {
|
|
|
|
if (*it == delim_end[delim_p] && ++delim_p == delim_end.size()) {
|
|
|
|
pstate = parse_state::start;
|
|
|
|
out += state.top()->render(*this, {false, {tok_start,tok_end}});
|
|
|
|
out += state.top()->render(*this, {true, {tok_end, it + 1}});
|
|
|
|
tok_start = it + 1;
|
|
|
|
} else {
|
|
|
|
pstate = parse_state::start;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
out += state.top()->render(*this, {false, {tok_start, t.end()}});
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string render_context::render(const std::vector<token>& tokens) {
|
|
|
|
std::string output;
|
|
|
|
for(auto& token: tokens)
|
|
|
|
output += state.top()->render(*this, token);
|
|
|
|
return output;
|
2015-04-09 20:41:27 +02:00
|
|
|
}
|
2015-04-12 17:11:49 +02:00
|
|
|
|
|
|
|
std::string render_context::render_partial(const std::string& partial_name) {
|
|
|
|
return (partials.count(partial_name))?render(partials.at(partial_name)):"";
|
|
|
|
}
|