mstch/src/render_context.cpp

151 lines
5.3 KiB
C++
Raw Normal View History

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-15 01:42:51 +02:00
context.objects.emplace_front(obj);
context.state.push(std::unique_ptr<state::render_state>(
new state::outside_section));
2015-04-13 02:15:51 +02:00
}
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},
2015-04-15 01:42:51 +02:00
objects{object},
delim_start{"{{"},
delim_end{"}}"}
2015-04-09 20:41:27 +02:00
{
2015-04-15 01:42:51 +02:00
state.push(std::unique_ptr<state::render_state>(new state::outside_section));
2015-04-09 20:41:27 +02:00
}
2015-04-10 12:56:08 +02:00
const mstch::node& render_context::find_node(
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-15 01:42:51 +02:00
void render_context::tokenize(const std::string& t, std::vector<token>& toks) {
2015-04-13 16:35:12 +02:00
std::string::const_iterator tok_end, tok_start = t.begin();
parse_state pstate = parse_state::start;
2015-04-15 01:42:51 +02:00
unsigned int del_pos = 0;
bool ws_only = true;
2015-04-13 16:35:12 +02:00
for (std::string::const_iterator it = t.begin(); it != t.end(); ++it) {
2015-04-15 16:13:23 +02:00
if (pstate == parse_state::start) {
if (*it == delim_start[0]) {
2015-04-15 01:42:51 +02:00
pstate = parse_state::in_del_start;
tok_end = it;
del_pos = 1;
} else if(*it == '\n') {
toks.push_back({false, true, ws_only, {tok_start, it + 1}});
ws_only = true;
tok_start = it + 1;
} else if (*it != ' ' && *it != '\t') {
ws_only = false;
}
2015-04-13 16:35:12 +02:00
} else if(pstate == parse_state::in_del_start) {
2015-04-15 01:42:51 +02:00
if (*it == delim_start[del_pos] && ++del_pos == delim_start.size())
2015-04-13 16:35:12 +02:00
pstate = parse_state::in_del;
else
pstate = parse_state::start;
} else if(pstate == parse_state::in_del) {
if (*it== '{') {
2015-04-15 01:42:51 +02:00
pstate = parse_state::in_esccontent;
2015-04-13 16:35:12 +02:00
} else if (*it == delim_end[0]) {
pstate = parse_state::in_del_end;
2015-04-15 01:42:51 +02:00
del_pos = 1;
2015-04-13 16:35:12 +02:00
} else {
pstate = parse_state::in_content;
}
2015-04-15 01:42:51 +02:00
} else if(pstate == parse_state::in_esccontent && *it == '}') {
2015-04-13 16:35:12 +02:00
pstate = parse_state::in_content;
} else if(pstate == parse_state::in_content && *it == delim_end[0]) {
pstate = parse_state::in_del_end;
2015-04-15 01:42:51 +02:00
del_pos = 1;
2015-04-13 16:35:12 +02:00
} else if(pstate == parse_state::in_del_end) {
2015-04-15 01:42:51 +02:00
if (*it == delim_end[del_pos] && ++del_pos == delim_end.size()) {
2015-04-13 16:35:12 +02:00
pstate = parse_state::start;
2015-04-15 01:42:51 +02:00
toks.push_back({false, false, ws_only, {tok_start, tok_end}});
2015-04-15 16:13:23 +02:00
toks.push_back({true, false, false,
{tok_end +delim_start.size(), it - delim_end.size() +1}});
2015-04-15 01:42:51 +02:00
ws_only = true;
2015-04-13 16:35:12 +02:00
tok_start = it + 1;
} else {
pstate = parse_state::start;
}
}
}
2015-04-15 01:42:51 +02:00
toks.push_back({false, false, ws_only, {tok_start, t.end()}});
}
void render_context::strip_whitespace(std::vector<token>& tokens) {
auto line_begin = tokens.begin();
bool has_tag = false, non_space = false;
2015-04-15 16:13:23 +02:00
for (auto it = tokens.begin(); it != tokens.end(); ++it) {
2015-04-15 01:42:51 +02:00
auto type = (*it).token_type();
2015-04-15 16:13:23 +02:00
if (type != token::type::text && type != token::type::variable &&
2015-04-15 01:42:51 +02:00
type != token::type::unescaped_variable)
has_tag = true;
2015-04-15 16:13:23 +02:00
else if (!(*it).is_ws_only())
2015-04-15 01:42:51 +02:00
non_space = true;
2015-04-15 16:13:23 +02:00
if ((*it).is_eol()) {
if (has_tag && !non_space)
2015-04-15 01:42:51 +02:00
for (auto line_it = line_begin; line_it != it + 1; ++line_it)
if ((*line_it).is_ws_only())
(*line_it).mark();
non_space = has_tag = false;
line_begin = it + 1;
}
}
2015-04-15 16:13:23 +02:00
for (auto it = tokens.begin(); it != tokens.end();)
2015-04-15 01:42:51 +02:00
((*it).is_marked())?(it = tokens.erase(it)):(++it);
}
std::string render_context::render(const std::string& tmplt) {
std::vector<token> tokens;
tokenize(tmplt, tokens);
strip_whitespace(tokens);
return render(tokens);
2015-04-13 16:35:12 +02:00
}
std::string render_context::render(const std::vector<token>& tokens) {
std::string output;
2015-04-15 16:13:23 +02:00
for (auto& token: tokens)
2015-04-13 16:35:12 +02:00
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)):"";
}