full lambda support

This commit is contained in:
Daniel Sipka 2015-04-23 15:55:18 +02:00
parent f4dd438fcc
commit 7bdde0783f
38 changed files with 142 additions and 207 deletions

View file

@ -40,17 +40,25 @@ using renderer = std::function<std::string(const std::string&)>;
class lambda { class lambda {
public: public:
lambda(std::function<std::string(const std::string&,renderer)> fun): lambda(std::function<std::string()> fun):
fun([fun](const std::string&, renderer){return fun();})
{
}
lambda(std::function<std::string(const std::string&, renderer)> fun):
fun(fun) fun(fun)
{ {
} }
std::string operator()(const std::string& text, renderer renderer) const { std::string operator()(
const std::string& text = "",
renderer renderer = renderer()) const
{
return fun(text, renderer); return fun(text, renderer);
} }
private: private:
std::function<std::string(const std::string&,renderer)> fun; std::function<std::string(const std::string&, renderer)> fun;
}; };
using node = boost::make_recursive_variant< using node = boost::make_recursive_variant<

View file

@ -8,6 +8,12 @@ include_directories(
set(SRC set(SRC
state/in_section.cpp state/in_section.cpp
state/outside_section.cpp state/outside_section.cpp
state/render_state.hpp
visitor/get_token.hpp
visitor/has_token.hpp
visitor/is_node_empty.hpp
visitor/render_node.hpp
visitor/render_section.hpp
mstch.cpp mstch.cpp
render_context.cpp render_context.cpp
template_type.cpp template_type.cpp

View file

@ -11,8 +11,8 @@ std::string mstch::render(
const node& root, const node& root,
const std::map<std::string,std::string>& partials) const std::map<std::string,std::string>& partials)
{ {
std::map<std::string, template_type> partial_templts; std::map<std::string, template_type> partial_templates;
for (auto& partial: partials) for (auto& partial: partials)
partial_templts.insert({partial.first, {partial.second}}); partial_templates.insert({partial.first, {partial.second}});
return render_context(root, partial_templts).render(tmplt); return render_context(root, partial_templates).render(tmplt);
} }

View file

@ -5,7 +5,6 @@
#include "visitor/has_token.hpp" #include "visitor/has_token.hpp"
using namespace mstch; using namespace mstch;
using namespace mstch::visitor;
const mstch::node render_context::null_node; const mstch::node render_context::null_node;
@ -13,8 +12,7 @@ render_context::push::push(render_context& context, const mstch::node& node):
context(context) context(context)
{ {
context.nodes.emplace_front(node); context.nodes.emplace_front(node);
context.state.push(std::unique_ptr<state::render_state>( context.state.push(std::unique_ptr<render_state>(new outside_section));
new state::outside_section));
} }
render_context::push::~push() { render_context::push::~push() {
@ -29,11 +27,9 @@ std::string render_context::push::render(const template_type& templt) {
render_context::render_context( render_context::render_context(
const mstch::node& node, const mstch::node& node,
const std::map<std::string, template_type>& partials): const std::map<std::string, template_type>& partials):
partials{partials}, partials{partials}, nodes{node}
nodes{node}
{ {
state.push(std::unique_ptr<state::render_state>( state.push(std::unique_ptr<render_state>(new outside_section));
new state::outside_section));
} }
const mstch::node& render_context::find_node( const mstch::node& render_context::find_node(
@ -41,8 +37,7 @@ const mstch::node& render_context::find_node(
const std::deque<node>& current_nodes) const std::deque<node>& current_nodes)
{ {
if (token != "." && token.find('.') != std::string::npos) if (token != "." && token.find('.') != std::string::npos)
return find_node( return find_node(token.substr(token.rfind('.') + 1),
token.substr(token.rfind('.') + 1),
{find_node(token.substr(0, token.rfind('.')), current_nodes)}); {find_node(token.substr(0, token.rfind('.')), current_nodes)});
else else
for (auto& node: current_nodes) for (auto& node: current_nodes)

View file

@ -30,7 +30,7 @@ class render_context {
std::string render_partial(const std::string& partial_name); std::string render_partial(const std::string& partial_name);
template<class T, class... Args> template<class T, class... Args>
void set_state(Args&& ... args) { void set_state(Args&& ... args) {
state.top() = std::unique_ptr<state::render_state>( state.top() = std::unique_ptr<render_state>(
new T(std::forward<Args>(args)...)); new T(std::forward<Args>(args)...));
} }
@ -41,7 +41,7 @@ class render_context {
const std::deque<node>& current_nodes); const std::deque<node>& current_nodes);
const std::map<std::string, template_type>& partials; const std::map<std::string, template_type>& partials;
std::deque<mstch::node> nodes; std::deque<mstch::node> nodes;
std::stack<std::unique_ptr<state::render_state>> state; std::stack<std::unique_ptr<render_state>> state;
}; };
} }

View file

@ -5,14 +5,13 @@
#include "utils.hpp" #include "utils.hpp"
using namespace mstch; using namespace mstch;
using namespace mstch::visitor;
state::in_section::in_section(type type, const std::string& section_name): in_section::in_section(type type, const std::string& section_name):
m_type(type), section_name(section_name), skipped_openings(0) m_type(type), section_name(section_name), skipped_openings(0)
{ {
} }
std::string state::in_section::render(render_context& ctx, const token& token) { std::string in_section::render(render_context& ctx, const token& token) {
if (token.token_type() == token::type::section_close) if (token.token_type() == token::type::section_close)
if (token.name() == section_name && skipped_openings == 0) { if (token.name() == section_name && skipped_openings == 0) {
auto& node = ctx.get_node(section_name); auto& node = ctx.get_node(section_name);

View file

@ -7,7 +7,6 @@
#include "template_type.hpp" #include "template_type.hpp"
namespace mstch { namespace mstch {
namespace state {
class in_section: public render_state { class in_section: public render_state {
public: public:
@ -25,4 +24,3 @@ class in_section: public render_state {
}; };
} }
}

View file

@ -6,9 +6,8 @@
#include "utils.hpp" #include "utils.hpp"
using namespace mstch; using namespace mstch;
using namespace mstch::visitor;
std::string state::outside_section::render( std::string outside_section::render(
render_context& ctx, const token& token) render_context& ctx, const token& token)
{ {
using flag = render_node::flag; using flag = render_node::flag;

View file

@ -3,7 +3,6 @@
#include "render_state.hpp" #include "render_state.hpp"
namespace mstch { namespace mstch {
namespace state {
class outside_section: public render_state { class outside_section: public render_state {
public: public:
@ -11,4 +10,3 @@ class outside_section: public render_state {
}; };
} }
}

View file

@ -8,12 +8,9 @@ namespace mstch {
class render_context; class render_context;
namespace state {
class render_state { class render_state {
public: public:
virtual std::string render(render_context& context, const token& token) = 0; virtual std::string render(render_context& context, const token& token) = 0;
}; };
} }
}

View file

@ -13,7 +13,7 @@ citer first_not_ws(criter begin, criter end);
std::string html_escape(std::string str); std::string html_escape(std::string str);
template<class... Args> template<class... Args>
auto visit(Args&& ... args) -> decltype(boost::apply_visitor( auto visit(Args&&... args) -> decltype(boost::apply_visitor(
std::forward<Args>(args)...)) std::forward<Args>(args)...))
{ {
return boost::apply_visitor(std::forward<Args>(args)...); return boost::apply_visitor(std::forward<Args>(args)...);

View file

@ -4,9 +4,9 @@
#include <boost/blank.hpp> #include <boost/blank.hpp>
#include "mstch/mstch.hpp" #include "mstch/mstch.hpp"
#include "has_token.hpp"
namespace mstch { namespace mstch {
namespace visitor {
class get_token: public boost::static_visitor<const mstch::node&> { class get_token: public boost::static_visitor<const mstch::node&> {
public: public:
@ -38,4 +38,3 @@ inline const mstch::node& get_token::operator()<std::shared_ptr<object>>(
} }
} }
}

View file

@ -6,7 +6,6 @@
#include "mstch/mstch.hpp" #include "mstch/mstch.hpp"
namespace mstch { namespace mstch {
namespace visitor {
class has_token: public boost::static_visitor<bool> { class has_token: public boost::static_visitor<bool> {
public: public:
@ -17,7 +16,8 @@ class has_token: public boost::static_visitor<bool> {
inline bool operator()(const T& t) const { inline bool operator()(const T& t) const {
return token == "."; return token == ".";
} }
private:
private:
const std::string& token; const std::string& token;
}; };
@ -34,4 +34,3 @@ inline bool has_token::operator()<std::shared_ptr<object>>(
} }
} }
}

View file

@ -6,7 +6,6 @@
#include "mstch/mstch.hpp" #include "mstch/mstch.hpp"
namespace mstch { namespace mstch {
namespace visitor {
class is_node_empty: public boost::static_visitor<bool> { class is_node_empty: public boost::static_visitor<bool> {
public: public:
@ -24,20 +23,20 @@ inline bool is_node_empty::operator()<boost::blank>(
} }
template<> template<>
inline bool is_node_empty::operator()<int>(const int& val) const { inline bool is_node_empty::operator()<int>(const int& value) const {
return val == 0; return value == 0;
} }
template<> template<>
inline bool is_node_empty::operator()<bool>(const bool& val) const { inline bool is_node_empty::operator()<bool>(const bool& value) const {
return !val; return !value;
} }
template<> template<>
inline bool is_node_empty::operator()<std::string>( inline bool is_node_empty::operator()<std::string>(
const std::string& val) const const std::string& value) const
{ {
return val == ""; return value == "";
} }
template<> template<>
@ -46,4 +45,3 @@ inline bool is_node_empty::operator()<array>(const array& array) const {
} }
} }
}

View file

@ -7,7 +7,6 @@
#include "utils.hpp" #include "utils.hpp"
namespace mstch { namespace mstch {
namespace visitor {
class render_node: public boost::static_visitor<std::string> { class render_node: public boost::static_visitor<std::string> {
public: public:
@ -28,21 +27,25 @@ class render_node: public boost::static_visitor<std::string> {
}; };
template<> template<>
inline std::string render_node::operator()<int>(const int& val) const { inline std::string render_node::operator()<int>(const int& value) const {
return std::to_string(val); return std::to_string(value);
} }
template<> inline template<>
std::string render_node::operator()<bool>(const bool& val) const { inline std::string render_node::operator()<bool>(const bool& value) const {
return val?"true":"false"; return value?"true":"false";
}
template<>
inline std::string render_node::operator()<lambda>(const lambda& value) const {
return (m_flag == flag::escape_html)?html_escape(value()):value();
} }
template<> template<>
inline std::string render_node::operator()<std::string>( inline std::string render_node::operator()<std::string>(
const std::string& val) const const std::string& value) const
{ {
return (m_flag == flag::escape_html)?html_escape(val):val; return (m_flag == flag::escape_html)?html_escape(value):value;
} }
} }
}

View file

@ -8,7 +8,6 @@
#include "utils.hpp" #include "utils.hpp"
namespace mstch { namespace mstch {
namespace visitor {
class render_section: public boost::static_visitor<std::string> { class render_section: public boost::static_visitor<std::string> {
public: public:
@ -26,7 +25,7 @@ class render_section: public boost::static_visitor<std::string> {
return render_context::push(ctx, t).render(section); return render_context::push(ctx, t).render(section);
} }
private: private:
render_context& ctx; render_context& ctx;
const template_type& section; const template_type& section;
flag m_flag; flag m_flag;
@ -34,13 +33,12 @@ private:
template<> template<>
inline std::string render_section::operator()<lambda>(const lambda& fun) const { inline std::string render_section::operator()<lambda>(const lambda& fun) const {
return ""; std::string section_str;
/*std::string section_str;
for(auto& token: section) for(auto& token: section)
section_str += token.raw(); section_str += token.raw();
return lam(section_str, [this](const std::string& str) { return fun(section_str, [this](const std::string& str) {
return ctx.render(template_type{str}); return render_context::push(ctx).render(template_type{str});
});*/ });
} }
template<> template<>
@ -55,4 +53,3 @@ inline std::string render_section::operator()<array>(const array& array) const {
} }
} }
}

View file

@ -12,8 +12,8 @@ int main() {
std::string comment_tmp{ std::string comment_tmp{
"<div class=\"comments\"><h3>{{header}}</h3><ul>" "<div class=\"comments\"><h3>{{header}}</h3><ul>"
"{{#comments}}<li class=\"comment\"><h5>{{name}}</h5>" "{{#comments}}<li class=\"comment\"><h5>{{name}}</h5>"
"<p>{{body}}</p></li>{{/comments}}</ul></div>" "<p>{{body}}</p></li>{{/comments}}</ul></div>"};
};
auto comment_view = mstch::map{ auto comment_view = mstch::map{
{"header", std::string{"My Post Comments"}}, {"header", std::string{"My Post Comments"}},
{"comments", mstch::array{ {"comments", mstch::array{
@ -21,9 +21,7 @@ int main() {
mstch::map{{"name", std::string{"Sam"}}, {"body", std::string{"Thanks for this post!"}}}, mstch::map{{"name", std::string{"Sam"}}, {"body", std::string{"Thanks for this post!"}}},
mstch::map{{"name", std::string{"Heather"}}, {"body", std::string{"Thanks for this post!"}}}, mstch::map{{"name", std::string{"Heather"}}, {"body", std::string{"Thanks for this post!"}}},
mstch::map{{"name", std::string{"Kathy"}}, {"body", std::string{"Thanks for this post!"}}}, mstch::map{{"name", std::string{"Kathy"}}, {"body", std::string{"Thanks for this post!"}}},
mstch::map{{"name", std::string{"George"}}, {"body", std::string{"Thanks for this post!"}}} mstch::map{{"name", std::string{"George"}}, {"body", std::string{"Thanks for this post!"}}}}}};
}}
};
std::vector<unsigned long> times; std::vector<unsigned long> times;
for (int j = 0; j < 10; j++) { for (int j = 0; j < 10; j++) {

View file

@ -1,3 +1,3 @@
const auto bug_11_eating_whitespace_data = mstch::map{ const auto bug_11_eating_whitespace_data = mstch::map{
{"tag", std::string{"yo"}} {"tag", std::string{"yo"}}
}; };

View file

@ -1,12 +1,3 @@
class comments: public mstch::object { const mstch::node comments_data = mstch::map{
public: {"title", mstch::lambda{[](){return std::string{"A Comedy of Errors"};}}}
comments() { };
register_methods(this, {{"title", &comments::title}});
}
mstch::node title() {
return std::string{"A Comedy of Errors"};
}
};
const mstch::node comments_data = std::make_shared<comments>();

View file

@ -45,7 +45,8 @@ public:
{ {
register_methods(this, { register_methods(this, {
{"header", &complex::header}, {"item", &complex::item}, {"header", &complex::header}, {"item", &complex::item},
{"list", &complex::list}, {"empty", &complex::empty}}); {"list", &complex::list}, {"empty", &complex::empty}
});
} }
mstch::node header() { mstch::node header() {

View file

@ -1,18 +1,4 @@
class escaped: public mstch::object { const mstch::node escaped_data = mstch::map{
public: {"title", mstch::lambda{[](){ return std::string{"Bear > Shark"}; }}},
escaped() { {"entities", mstch::lambda{[](){ return std::string{"&quot; \"'<>/"}; }}}
register_methods(this, { };
{"title", &escaped::title}, {"entities", &escaped::entities}
});
}
mstch::node title() {
return std::string{"Bear > Shark"};
};
mstch::node entities() {
return std::string{"&quot; \"'<>/"};
}
};
const mstch::node escaped_data = std::make_shared<escaped>();

View file

@ -3,6 +3,6 @@ const auto falsy_array_data = mstch::map{
mstch::array{std::string{""}, std::string{"emptyString"}}, mstch::array{std::string{""}, std::string{"emptyString"}},
mstch::array{mstch::array{}, std::string{"emptyArray"}}, mstch::array{mstch::array{}, std::string{"emptyArray"}},
mstch::array{0, std::string{"zero"}}, mstch::array{0, std::string{"zero"}},
mstch::array{mstch::node{}, std::string{"null"}} mstch::array{mstch::node{}, std::string{"null"}}}
}} }
}; };

View file

@ -0,0 +1,28 @@
class higher_order_sections: public mstch::object {
private:
std::string m_helper;
public:
higher_order_sections(): m_helper{"To tinker?"} {
register_methods(this, {
{"name", &higher_order_sections::name},
{"helper", &higher_order_sections::helper},
{"bolder", &higher_order_sections::bolder}
});
}
mstch::node name() {
return std::string{"Tater"};
}
mstch::node helper() {
return m_helper;
}
mstch::node bolder() {
return mstch::lambda{[this](const std::string& text, mstch::renderer render) {
return text + " => <b>" + render(text) + "</b> " + m_helper;
}};
}
};
const mstch::node higher_order_sections_data = std::make_shared<higher_order_sections>();

View file

@ -1,7 +0,0 @@
({
number: function(text, render) {
return function(text, render) {
return +render(text);
}
}
})

View file

@ -1 +0,0 @@
<p>{{#number}}0{{/number}}</p>

View file

@ -1 +0,0 @@
<p>0</p>

View file

@ -1,9 +0,0 @@
({
name: "Tater",
helper: "To tinker?",
bolder: function () {
return function (text, render) {
return text + ' => <b>' + render(text) + '</b> ' + this.helper;
}
}
})

View file

@ -1,21 +1,6 @@
class nested_higher_order_sections: public mstch::object { const mstch::node nested_higher_order_sections_data = mstch::map{
public: {"bold", mstch::lambda{[](const std::string& text, mstch::renderer render) {
nested_higher_order_sections() { return std::string{"<b>"} + render(text) + std::string{"</b>"};
register_methods(this, { }}},
{"bold", &nested_higher_order_sections::bold}, {"person", mstch::map{{"name", std::string{"Jonas"}}}}
{"person", &nested_higher_order_sections::person} };
});
}
mstch::node bold() {
return mstch::lambda{[](const std::string& text, mstch::renderer render) {
return std::string{"<b>"} + render(text) + std::string{"</b>"};
}};
};
mstch::node person() {
return mstch::map{{"name", std::string{"Jonas"}}};
}
};
const mstch::node nested_higher_order_sections_data = std::make_shared<nested_higher_order_sections>();

View file

@ -1,14 +1,14 @@
const auto null_lookup_object_data = mstch::map{ const auto null_lookup_object_data = mstch::map{
{"name", std::string{"David"}}, {"name", std::string{"David"}},
{"twitter", std::string{"@dasilvacontin"}}, {"twitter", std::string{"@dasilvacontin"}},
{"fobject", mstch::array{ {"fobject", mstch::array{
mstch::map{ mstch::map{
{"name", std::string{"Flor"}}, {"name", std::string{"Flor"}},
{"twitter", std::string{"@florrts"}} {"twitter", std::string{"@florrts"}}
}, },
mstch::map{ mstch::map{
{"name", std::string{"Miquel"}}, {"name", std::string{"Miquel"}},
{"twitter", mstch::node{}} {"twitter", mstch::node{}}
} }
}} }}
}; };

View file

@ -1,18 +1,4 @@
class partial_template: public mstch::object { const mstch::node partial_template_data = mstch::map{
public: {"title", mstch::lambda{[](){ return std::string{"Welcome"}; }}},
partial_template() { {"again", mstch::lambda{[](){ return std::string{"Goodbye"}; }}},
register_methods(this, { };
{"title", &partial_template::title},
{"again", &partial_template::again}});
}
mstch::node title() {
return std::string{"Welcome"};
}
mstch::node again() {
return std::string{"Goodbye"};
}
};
const auto partial_template_data = std::make_shared<partial_template>();

View file

@ -9,7 +9,8 @@ public:
{"name", &partial_view::name}, {"name", &partial_view::name},
{"value", &partial_view::value}, {"value", &partial_view::value},
{"taxed_value", &partial_view::taxed_value}, {"taxed_value", &partial_view::taxed_value},
{"in_ca", &partial_view::in_ca},}); {"in_ca", &partial_view::in_ca}
});
} }
mstch::node greeting() { mstch::node greeting() {

View file

@ -9,7 +9,8 @@ public:
{"name", &partial_whitespace::name}, {"name", &partial_whitespace::name},
{"value", &partial_whitespace::value}, {"value", &partial_whitespace::value},
{"taxed_value", &partial_whitespace::taxed_value}, {"taxed_value", &partial_whitespace::taxed_value},
{"in_ca", &partial_whitespace::in_ca},}); {"in_ca", &partial_whitespace::in_ca}
});
} }
mstch::node greeting() { mstch::node greeting() {

View file

@ -1,15 +1,5 @@
class section_functions_in_partials: public mstch::object { const mstch::node section_functions_in_partials_data = mstch::map{
public: {"bold", mstch::lambda{[](const std::string& text, mstch::renderer render) {
section_functions_in_partials() { return std::string{"<b>"} + render(text) + std::string{"</b>"};
register_methods(this, {{"bold", &section_functions_in_partials::bold}}); }}}
} };
mstch::node bold() {
return std::string{""};
/*return [](const std::string& text, mstch::renderer render) {
return std::string{"<b>"} + render(text) + std::string{"</b>"};
};*/
}
};
const auto section_functions_in_partials_data = std::make_shared<section_functions_in_partials>();

View file

@ -1,21 +1,19 @@
class simple: public mstch::object { class simple: public mstch::object {
private: private:
std::string m_name;
int m_value; int m_value;
bool m_in_ca;
public: public:
simple(): simple():
m_name{"Chris"}, m_value{10000}
m_value{10000},
m_in_ca{true}
{ {
register_methods(this, { register_methods(this, {
{"name", &simple::name}, {"value", &simple::value}, {"name", &simple::name},
{"taxed_value", &simple::taxed_value}, {"in_ca", &simple::in_ca}}); {"value", &simple::value},
{"taxed_value", &simple::taxed_value},
{"in_ca", &simple::in_ca}});
} }
mstch::node name() { mstch::node name() {
return m_name; return std::string{"Chris"};
} }
mstch::node value() { mstch::node value() {
@ -27,8 +25,8 @@ public:
} }
mstch::node in_ca() { mstch::node in_ca() {
return m_in_ca; return true;
} }
}; };
const auto simple_data = std::make_shared<simple>(); const auto simple_data = std::make_shared<simple>();

View file

@ -1,12 +1,3 @@
class unescaped: public mstch::object { const mstch::node unescaped_data = mstch::map{
public: {"title", mstch::lambda{[](){ return std::string{"Bear > Shark"}; }}}
unescaped() { };
register_methods(this, {{"title", &unescaped::title}});
}
mstch::node title() {
return std::string{"Bear > Shark"};
}
};
const auto unescaped_data = std::make_shared<unescaped>();

View file

@ -35,13 +35,14 @@ MSTCH_TEST(escaped)
MSTCH_TEST(falsy) MSTCH_TEST(falsy)
MSTCH_TEST(falsy_array) MSTCH_TEST(falsy_array)
MSTCH_TEST(grandparent_context) MSTCH_TEST(grandparent_context)
MSTCH_TEST(higher_order_sections)
MSTCH_TEST(implicit_iterator) MSTCH_TEST(implicit_iterator)
MSTCH_TEST(included_tag) MSTCH_TEST(included_tag)
MSTCH_TEST(inverted_section) MSTCH_TEST(inverted_section)
MSTCH_TEST(keys_with_questionmarks) MSTCH_TEST(keys_with_questionmarks)
MSTCH_TEST(multiline_comment) MSTCH_TEST(multiline_comment)
MSTCH_TEST(nested_dot) MSTCH_TEST(nested_dot)
//MSTCH_TEST(nested_higher_order_sections) MSTCH_TEST(nested_higher_order_sections)
MSTCH_TEST(nested_iterating) MSTCH_TEST(nested_iterating)
MSTCH_TEST(nesting) MSTCH_TEST(nesting)
MSTCH_TEST(nesting_same_name) MSTCH_TEST(nesting_same_name)
@ -59,7 +60,7 @@ MSTCH_PARTIAL_TEST(partial_whitespace)
MSTCH_TEST(recursion_with_same_names) MSTCH_TEST(recursion_with_same_names)
MSTCH_TEST(reuse_of_enumerables) MSTCH_TEST(reuse_of_enumerables)
MSTCH_TEST(section_as_context) MSTCH_TEST(section_as_context)
//MSTCH_PARTIAL_TEST(section_functions_in_partials) MSTCH_PARTIAL_TEST(section_functions_in_partials)
MSTCH_TEST(simple) MSTCH_TEST(simple)
MSTCH_TEST(string_as_context) MSTCH_TEST(string_as_context)
MSTCH_TEST(two_in_a_row) MSTCH_TEST(two_in_a_row)