extract template_type from render_context
This commit is contained in:
parent
ba64f4e541
commit
dc513839bd
@ -6,15 +6,16 @@ include_directories(
|
||||
${Boost_INCLUDE_DIR})
|
||||
|
||||
set(SRC
|
||||
mstch.cpp
|
||||
utils.cpp
|
||||
token.cpp
|
||||
render_context.cpp
|
||||
state/in_section.cpp
|
||||
state/in_inverted_section.cpp
|
||||
state/in_section.cpp
|
||||
state/outside_section.cpp
|
||||
visitor/is_node_empty.cpp
|
||||
visitor/render_node.cpp
|
||||
visitor/render_section.cpp)
|
||||
visitor/render_section.cpp
|
||||
mstch.cpp
|
||||
render_context.cpp
|
||||
template_type.cpp
|
||||
token.cpp
|
||||
utils.cpp)
|
||||
|
||||
add_library(mstch STATIC ${SRC})
|
||||
|
@ -11,5 +11,8 @@ std::string mstch::render(
|
||||
const object& root,
|
||||
const std::map<std::string,std::string>& partials)
|
||||
{
|
||||
return render_context(root, partials).render(tmplt);
|
||||
std::map<std::string,template_type> partial_templts;
|
||||
for(auto& partial: partials)
|
||||
partial_templts.insert({partial.first, {partial.second}});
|
||||
return render_context(root, partial_templts).render(tmplt);
|
||||
}
|
||||
|
@ -19,17 +19,15 @@ render_context::push::~push() {
|
||||
context.state.pop();
|
||||
}
|
||||
|
||||
std::string render_context::push::render(const std::vector<token>& tokens) {
|
||||
return context.render(tokens);
|
||||
std::string render_context::push::render(const template_type& templt) {
|
||||
return context.render(templt);
|
||||
}
|
||||
|
||||
render_context::render_context(
|
||||
const mstch::object& object,
|
||||
const std::map<std::string,std::string>& partials):
|
||||
const std::map<std::string,template_type>& partials):
|
||||
partials{partials},
|
||||
objects{object},
|
||||
delim_start{"{{"},
|
||||
delim_end{"}}"}
|
||||
objects{object}
|
||||
{
|
||||
state.push(std::unique_ptr<state::render_state>(
|
||||
new state::outside_section));
|
||||
@ -56,91 +54,9 @@ const mstch::node& render_context::get_node(const std::string& token) {
|
||||
return find_node(token, objects);
|
||||
}
|
||||
|
||||
void render_context::tokenize(const std::string& t, std::vector<token>& toks) {
|
||||
std::string::const_iterator tok_end, tok_start = t.begin();
|
||||
parse_state pstate = parse_state::start;
|
||||
unsigned int del_pos = 0;
|
||||
bool ws_only = true;
|
||||
for (std::string::const_iterator it = t.begin(); it != t.end(); ++it) {
|
||||
if (pstate == parse_state::start) {
|
||||
if (*it == delim_start[0]) {
|
||||
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;
|
||||
}
|
||||
} else if(pstate == parse_state::in_del_start) {
|
||||
if (*it == delim_start[del_pos] && ++del_pos == 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_esccontent;
|
||||
} else if (*it == delim_end[0]) {
|
||||
pstate = parse_state::in_del_end;
|
||||
del_pos = 1;
|
||||
} else {
|
||||
pstate = parse_state::in_content;
|
||||
}
|
||||
} else if(pstate == parse_state::in_esccontent && *it == '}') {
|
||||
pstate = parse_state::in_content;
|
||||
} else if(pstate == parse_state::in_content && *it == delim_end[0]) {
|
||||
pstate = parse_state::in_del_end;
|
||||
del_pos = 1;
|
||||
} else if(pstate == parse_state::in_del_end) {
|
||||
if (*it == delim_end[del_pos] && ++del_pos == delim_end.size()) {
|
||||
pstate = parse_state::start;
|
||||
toks.push_back({false, false, ws_only, {tok_start, tok_end}});
|
||||
toks.push_back({true, false, false,
|
||||
{tok_end+delim_start.size(), it-delim_end.size()+1}});
|
||||
ws_only = true;
|
||||
tok_start = it + 1;
|
||||
} else {
|
||||
pstate = parse_state::start;
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
for (auto it = tokens.begin(); it != tokens.end(); ++it) {
|
||||
auto type = (*it).token_type();
|
||||
if (type != token::type::text && type != token::type::variable &&
|
||||
type != token::type::unescaped_variable)
|
||||
has_tag = true;
|
||||
else if (!(*it).ws_only())
|
||||
non_space = true;
|
||||
if ((*it).eol()) {
|
||||
if (has_tag && !non_space)
|
||||
for (auto line_it = line_begin; line_it != it + 1; ++line_it)
|
||||
if ((*line_it).ws_only()) (*line_it).mark();
|
||||
non_space = has_tag = false;
|
||||
line_begin = it + 1;
|
||||
}
|
||||
}
|
||||
for (auto it = tokens.begin(); it != tokens.end();)
|
||||
((*it).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);
|
||||
}
|
||||
|
||||
std::string render_context::render(const std::vector<token>& tokens) {
|
||||
std::string render_context::render(const template_type& templt) {
|
||||
std::string output;
|
||||
for (auto& token: tokens)
|
||||
for (auto& token: templt)
|
||||
output += state.top()->render(*this, token);
|
||||
return output;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "mstch/mstch.hpp"
|
||||
#include "state/render_state.hpp"
|
||||
#include "template_type.hpp"
|
||||
|
||||
namespace mstch {
|
||||
class render_context {
|
||||
@ -15,15 +16,15 @@ namespace mstch {
|
||||
public:
|
||||
push(render_context& context, const mstch::object& obj = {});
|
||||
~push();
|
||||
std::string render(const std::vector<token>& tokens);
|
||||
std::string render(const template_type& templt);
|
||||
private:
|
||||
render_context& context;
|
||||
};
|
||||
render_context(
|
||||
const mstch::object& object,
|
||||
const std::map<std::string,std::string>& partials);
|
||||
const std::map<std::string,template_type>& partials);
|
||||
const mstch::node& get_node(const std::string& token);
|
||||
std::string render(const std::string& tmplt);
|
||||
std::string render(const template_type& templt);
|
||||
std::string render_partial(const std::string& partial_name);
|
||||
template<class T, class... Args>
|
||||
void set_state(Args&&... args) {
|
||||
@ -31,20 +32,12 @@ namespace mstch {
|
||||
new T(std::forward<Args>(args)...));
|
||||
}
|
||||
private:
|
||||
enum class parse_state {
|
||||
start, in_del_start, in_del, in_content, in_esccontent, in_del_end
|
||||
};
|
||||
static const mstch::node null_node;
|
||||
const mstch::node& find_node(
|
||||
const std::string& token,
|
||||
const std::deque<object>& current_objects);
|
||||
void tokenize(const std::string& tmplt, std::vector<token>& tokens);
|
||||
void strip_whitespace(std::vector<token>& tokens);
|
||||
std::string render(const std::vector<token>& tokens);
|
||||
std::map<std::string,std::string> partials;
|
||||
const std::map<std::string,template_type>& partials;
|
||||
std::deque<mstch::object> objects;
|
||||
std::stack<std::unique_ptr<state::render_state>> state;
|
||||
std::string delim_start;
|
||||
std::string delim_end;
|
||||
};
|
||||
}
|
||||
|
@ -20,12 +20,12 @@ std::string state::in_inverted_section::render(
|
||||
std::string out;
|
||||
auto& section_node = ctx.get_node(section_name);
|
||||
if(boost::apply_visitor(visitor::is_node_empty(), section_node))
|
||||
out = render_context::push(ctx).render(section_tokens);
|
||||
out = render_context::push(ctx).render(section);
|
||||
ctx.set_state<outside_section>();
|
||||
return out;
|
||||
} else {
|
||||
skipped_openings--;
|
||||
section_tokens.push_back(token);
|
||||
section << token;
|
||||
}
|
||||
break;
|
||||
case token::type::inverted_section_open:
|
||||
@ -36,7 +36,7 @@ std::string state::in_inverted_section::render(
|
||||
case token::type::unescaped_variable:
|
||||
case token::type::comment:
|
||||
case token::type::partial:
|
||||
section_tokens.push_back(token);
|
||||
section << token;
|
||||
break;
|
||||
};
|
||||
return "";
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <sstream>
|
||||
#include "render_state.hpp"
|
||||
#include <vector>
|
||||
#include "template_type.hpp"
|
||||
|
||||
namespace mstch {
|
||||
namespace state {
|
||||
@ -13,7 +14,7 @@ namespace mstch {
|
||||
render_context& context, const token& token) override;
|
||||
private:
|
||||
const std::string section_name;
|
||||
std::vector<token> section_tokens;
|
||||
template_type section;
|
||||
int skipped_openings;
|
||||
};
|
||||
}
|
||||
|
@ -18,13 +18,13 @@ std::string state::in_section::render(render_context& ctx, const token& token) {
|
||||
std::string out;
|
||||
if (!boost::apply_visitor(visitor::is_node_empty(), section_node))
|
||||
out = boost::apply_visitor(
|
||||
visitor::render_section(ctx, section_tokens),
|
||||
visitor::render_section(ctx, section),
|
||||
section_node);
|
||||
ctx.set_state<outside_section>();
|
||||
return out;
|
||||
} else {
|
||||
skipped_openings--;
|
||||
section_tokens.push_back(token);
|
||||
section << token;
|
||||
}
|
||||
break;
|
||||
case token::type::inverted_section_open:
|
||||
@ -35,7 +35,7 @@ std::string state::in_section::render(render_context& ctx, const token& token) {
|
||||
case token::type::unescaped_variable:
|
||||
case token::type::comment:
|
||||
case token::type::partial:
|
||||
section_tokens.push_back(token);
|
||||
section << token;
|
||||
break;
|
||||
}
|
||||
return "";
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "render_state.hpp"
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include "template_type.hpp"
|
||||
|
||||
namespace mstch {
|
||||
namespace state {
|
||||
@ -13,7 +14,7 @@ namespace mstch {
|
||||
render_context& context, const token& token) override;
|
||||
private:
|
||||
const std::string section_name;
|
||||
std::vector<token> section_tokens;
|
||||
template_type section;
|
||||
int skipped_openings;
|
||||
};
|
||||
}
|
||||
|
85
src/template_type.cpp
Normal file
85
src/template_type.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
#include "template_type.hpp"
|
||||
|
||||
using namespace mstch;
|
||||
|
||||
template_type::template_type(const std::string& str) {
|
||||
tokenize(str);
|
||||
strip_whitespace();
|
||||
}
|
||||
|
||||
void template_type::tokenize(const std::string& t) {
|
||||
std::string delim_start{"{{"};
|
||||
std::string delim_end{"}}"};
|
||||
std::string::const_iterator tok_end, tok_start = t.begin();
|
||||
parse_state pstate = parse_state::start;
|
||||
unsigned int del_pos = 0;
|
||||
bool ws_only = true;
|
||||
for (std::string::const_iterator it = t.begin(); it != t.end(); ++it) {
|
||||
if (pstate == parse_state::start) {
|
||||
if (*it == delim_start[0]) {
|
||||
pstate = parse_state::in_del_start;
|
||||
tok_end = it;
|
||||
del_pos = 1;
|
||||
} else if(*it == '\n') {
|
||||
tokens.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;
|
||||
}
|
||||
} else if(pstate == parse_state::in_del_start) {
|
||||
if (*it == delim_start[del_pos] && ++del_pos == 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_esccontent;
|
||||
} else if (*it == delim_end[0]) {
|
||||
pstate = parse_state::in_del_end;
|
||||
del_pos = 1;
|
||||
} else {
|
||||
pstate = parse_state::in_content;
|
||||
}
|
||||
} else if(pstate == parse_state::in_esccontent && *it == '}') {
|
||||
pstate = parse_state::in_content;
|
||||
} else if(pstate == parse_state::in_content && *it == delim_end[0]) {
|
||||
pstate = parse_state::in_del_end;
|
||||
del_pos = 1;
|
||||
} else if(pstate == parse_state::in_del_end) {
|
||||
if (*it == delim_end[del_pos] && ++del_pos == delim_end.size()) {
|
||||
pstate = parse_state::start;
|
||||
tokens.push_back({false, false, ws_only, {tok_start, tok_end}});
|
||||
tokens.push_back({true, false, false,
|
||||
{tok_end+delim_start.size(), it-delim_end.size()+1}});
|
||||
ws_only = true;
|
||||
tok_start = it + 1;
|
||||
} else {
|
||||
pstate = parse_state::start;
|
||||
}
|
||||
}
|
||||
}
|
||||
tokens.push_back({false, false, ws_only, {tok_start, t.end()}});
|
||||
}
|
||||
|
||||
void template_type::strip_whitespace() {
|
||||
auto line_begin = tokens.begin();
|
||||
bool has_tag = false, non_space = false;
|
||||
for (auto it = tokens.begin(); it != tokens.end(); ++it) {
|
||||
auto type = (*it).token_type();
|
||||
if (type != token::type::text && type != token::type::variable &&
|
||||
type != token::type::unescaped_variable)
|
||||
has_tag = true;
|
||||
else if (!(*it).ws_only())
|
||||
non_space = true;
|
||||
if ((*it).eol()) {
|
||||
if (has_tag && !non_space)
|
||||
for (auto line_it = line_begin; line_it != it + 1; ++line_it)
|
||||
if ((*line_it).ws_only()) (*line_it).mark();
|
||||
non_space = has_tag = false;
|
||||
line_begin = it + 1;
|
||||
}
|
||||
}
|
||||
for (auto it = tokens.begin(); it != tokens.end();)
|
||||
((*it).marked())?(it = tokens.erase(it)):(++it);
|
||||
}
|
24
src/template_type.hpp
Normal file
24
src/template_type.hpp
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "token.hpp"
|
||||
|
||||
namespace mstch {
|
||||
class template_type {
|
||||
public:
|
||||
template_type() = default;
|
||||
template_type(const std::string& str);
|
||||
std::vector<token>::const_iterator begin() const{return tokens.begin();}
|
||||
std::vector<token>::const_iterator end() const{return tokens.end();}
|
||||
void operator<<(const token& token) { tokens.push_back(token); }
|
||||
private:
|
||||
enum class parse_state {
|
||||
start, in_del_start, in_del, in_content, in_esccontent, in_del_end
|
||||
};
|
||||
void tokenize(const std::string& str);
|
||||
void strip_whitespace();
|
||||
std::vector<token> tokens;
|
||||
};
|
||||
}
|
@ -3,41 +3,41 @@
|
||||
using namespace mstch;
|
||||
|
||||
visitor::render_section::render_section(
|
||||
render_context& ctx, const std::vector<token>& section_tokens, std::set<flag> flags):
|
||||
ctx(ctx), section_tokens(section_tokens), flags(flags)
|
||||
render_context& ctx, const template_type& section,std::set<flag> flags):
|
||||
ctx(ctx), section(section), flags(flags)
|
||||
{
|
||||
}
|
||||
|
||||
std::string visitor::render_section::operator()(
|
||||
const boost::blank& blank) const
|
||||
{
|
||||
return render_context::push(ctx, {{".", {}}}).render(section_tokens);
|
||||
return render_context::push(ctx, {{".", {}}}).render(section);
|
||||
}
|
||||
|
||||
std::string visitor::render_section::operator()(const int& i) const {
|
||||
return render_context::push(ctx, {{".", i}}).render(section_tokens);
|
||||
return render_context::push(ctx, {{".", i}}).render(section);
|
||||
}
|
||||
|
||||
std::string visitor::render_section::operator()(const bool& b) const {
|
||||
return render_context::push(ctx, {{".", b}}).render(section_tokens);
|
||||
return render_context::push(ctx, {{".", b}}).render(section);
|
||||
}
|
||||
|
||||
std::string visitor::render_section::operator()(const std::string& str) const {
|
||||
return render_context::push(ctx, {{".", str}}).render(section_tokens);
|
||||
return render_context::push(ctx, {{".", str}}).render(section);
|
||||
}
|
||||
|
||||
std::string visitor::render_section::operator()(const object& obj) const {
|
||||
return render_context::push(ctx, obj).render(section_tokens);
|
||||
return render_context::push(ctx, obj).render(section);
|
||||
}
|
||||
|
||||
std::string visitor::render_section::operator()(const array& a) const {
|
||||
std::string out;
|
||||
if(flags.find(flag::keep_array) != flags.end())
|
||||
out += render_context::push(ctx, {{".", a}}).render(section_tokens);
|
||||
out += render_context::push(ctx, {{".", a}}).render(section);
|
||||
else
|
||||
for (auto& item: a)
|
||||
out += boost::apply_visitor(
|
||||
render_section(ctx, section_tokens, {flag::keep_array}), item);
|
||||
render_section(ctx, section, {flag::keep_array}), item);
|
||||
return out;
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@ std::string visitor::render_section::operator()(
|
||||
const renderer_lambda& lambda) const
|
||||
{
|
||||
return "";
|
||||
/*return (lambda())(section_tokens, [&](const std::string& text) {
|
||||
/*return (lambda())(section, [&](const std::string& text) {
|
||||
return render_context::push(ctx).render(text);
|
||||
}); TODO ! */
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ namespace mstch {
|
||||
enum class flag { keep_array };
|
||||
render_section(
|
||||
render_context& ctx,
|
||||
const std::vector<token>& section_tokens,
|
||||
const template_type& section,
|
||||
std::set<flag> flags = {});
|
||||
std::string operator()(const boost::blank& blank) const;
|
||||
std::string operator()(const int& i) const;
|
||||
@ -26,7 +26,7 @@ namespace mstch {
|
||||
std::string operator()(const renderer_lambda& lambda) const;
|
||||
private:
|
||||
render_context& ctx;
|
||||
const std::vector<token>& section_tokens;
|
||||
const template_type& section;
|
||||
std::set<flag> flags;
|
||||
};
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user