diff --git a/include/mstch/mstch.hpp b/include/mstch/mstch.hpp index 6462a2c..483cf4e 100644 --- a/include/mstch/mstch.hpp +++ b/include/mstch/mstch.hpp @@ -32,8 +32,21 @@ namespace mstch { }; } + using renderer = std::function; + class lambda { + public: + lambda(std::function fun): fun(fun) { + } + + std::string operator()(const std::string& text, renderer renderer) const { + return fun(text, renderer); + } + private: + std::function fun; + }; + using node = boost::make_recursive_variant< - boost::blank, std::string, int, bool, + boost::blank, std::string, int, bool, lambda, std::shared_ptr>, std::map, std::vector>::type; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8850707..f177b36 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -find_package(Boost 1.54 REQUIRED) +find_package(Boost 1.46 REQUIRED) include_directories( ${CMAKE_SOURCE_DIR}/include diff --git a/src/state/in_section.cpp b/src/state/in_section.cpp index db0cb89..64d881b 100644 --- a/src/state/in_section.cpp +++ b/src/state/in_section.cpp @@ -12,7 +12,7 @@ state::in_section::in_section(type type, const std::string& section_name): std::string state::in_section::render(render_context& ctx, const token& token) { if(token.token_type() == token::type::section_close) { - if(token.content() == section_name && skipped_openings == 0) { + if(token.name() == section_name && skipped_openings == 0) { auto& node = ctx.get_node(section_name); std::string out; if(m_type == type::normal) { diff --git a/src/state/outside_section.cpp b/src/state/outside_section.cpp index d209527..0f96926 100644 --- a/src/state/outside_section.cpp +++ b/src/state/outside_section.cpp @@ -10,23 +10,23 @@ std::string state::outside_section::render( { switch(token.token_type()) { case token::type::section_open: - ctx.set_state(in_section::type::normal, token.content()); + ctx.set_state(in_section::type::normal, token.name()); break; case token::type::inverted_section_open: - ctx.set_state(in_section::type::inverted, token.content()); + ctx.set_state(in_section::type::inverted, token.name()); break; case token::type::variable: return boost::apply_visitor( visitor::render_node(visitor::render_node::flag::escape_html), - ctx.get_node(token.content())); + ctx.get_node(token.name())); case token::type::unescaped_variable: return boost::apply_visitor( visitor::render_node(visitor::render_node::flag::none), - ctx.get_node(token.content())); + ctx.get_node(token.name())); case token::type::text: - return token.content(); + return token.raw(); case token::type::partial: - return ctx.render_partial(token.content()); + return ctx.render_partial(token.name()); default: break; } return ""; diff --git a/src/template_type.cpp b/src/template_type.cpp index 802fbba..3406ddb 100644 --- a/src/template_type.cpp +++ b/src/template_type.cpp @@ -13,7 +13,6 @@ void template_type::tokenize(const std::string& t) { 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]) { @@ -21,11 +20,8 @@ void template_type::tokenize(const std::string& t) { tok_end = it; del_pos = 1; } else if(*it == '\n') { - tokens.push_back({false, true, ws_only, {tok_start, it + 1}}); - ws_only = true; + tokens.push_back({{tok_start, it + 1}}); 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()) @@ -47,17 +43,15 @@ void template_type::tokenize(const std::string& t) { } 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; + tokens.push_back({{tok_start, tok_end}}); + tokens.push_back({{tok_end, it + 1}, delim_start.size(), delim_end.size()}); tok_start = it + 1; } else { pstate = parse_state::start; } } } - tokens.push_back({false, false, ws_only, {tok_start, t.end()}}); + tokens.push_back({{tok_start, t.end()}}); } void template_type::strip_whitespace() { @@ -71,13 +65,17 @@ void template_type::strip_whitespace() { 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(); + if (has_tag && !non_space) { + auto line_it = line_begin; + for (; !(*line_it).eol(); ++line_it) + if ((*line_it).ws_only()) + line_it = tokens.erase(line_it); + if ((*line_it).ws_only()) + line_it = tokens.erase(line_it); + it = line_it - 1; + } non_space = has_tag = false; line_begin = it + 1; } } - for (auto it = tokens.begin(); it != tokens.end();) - ((*it).marked())?(it = tokens.erase(it)):(++it); } diff --git a/src/token.cpp b/src/token.cpp index 2374aed..aef6416 100644 --- a/src/token.cpp +++ b/src/token.cpp @@ -15,23 +15,24 @@ token::type token::token_info(char c) { } } -token::token(bool is_tag, bool eol, bool ws_only, const std::string& str): - m_eol(eol), m_ws_only(ws_only), m_marked(false) +token::token(const std::string& str, std::size_t skip_left, std::size_t skip_right): + m_eol(false), m_ws_only(false), m_raw(str) { - if(is_tag) { - if(str[0] == '{' && str[str.size() - 1] == '}') { + if(skip_left != 0 && skip_right != 0) { + if(str[skip_left] == '{' && str[str.size() - skip_right - 1] == '}') { m_type = type::unescaped_variable; - m_content = {first_not_ws(str.begin() + 1, str.end()), - first_not_ws(str.rbegin() + 1, str.rend()) + 1}; + m_name = {first_not_ws(str.begin() + skip_left + 1, str.end() - skip_right), + first_not_ws(str.rbegin() + 1 + skip_right, str.rend() - skip_left) + 1}; } else { - auto first = first_not_ws(str.begin(), str.end()); + auto first = first_not_ws(str.begin() + skip_left, str.end() - skip_right); m_type = token_info(*first); if(m_type != type::variable) - first = first_not_ws(first + 1, str.end()); - m_content = {first, first_not_ws(str.rbegin(), str.rend()) + 1}; + first = first_not_ws(first + 1, str.end() - skip_right); + m_name = {first, first_not_ws(str.rbegin() + skip_right, str.rend() - skip_left) + 1}; } } else { m_type = type::text; - m_content = str; + m_eol = (str.size() > 0 && str[str.size() - 1] == '\n'); + m_ws_only = (str.find_first_not_of(" \n\t") == std::string::npos); } } diff --git a/src/token.hpp b/src/token.hpp index 56a7998..f57b5c3 100644 --- a/src/token.hpp +++ b/src/token.hpp @@ -9,19 +9,18 @@ namespace mstch { text, variable, section_open, section_close, inverted_section_open, unescaped_variable, comment, partial }; - token(bool is_tag, bool eol, bool ws_only, const std::string& str); + token(const std::string& str, std::size_t skip_left = 0, std::size_t skip_right = 0); type token_type() const { return m_type; }; - const std::string& content() const { return m_content; }; + const std::string& raw() const { return m_raw; }; + const std::string& name() const { return m_name; }; bool eol() const { return m_eol; } bool ws_only() const { return m_ws_only; } - bool marked() const { return m_marked; } - void mark() { m_marked = true; }; private: type m_type; - std::string m_content; + std::string m_name; + std::string m_raw; bool m_eol; bool m_ws_only; - bool m_marked; type token_info(char c); }; } diff --git a/src/visitor/render_section.hpp b/src/visitor/render_section.hpp index 6c4bc0b..ffb7340 100644 --- a/src/visitor/render_section.hpp +++ b/src/visitor/render_section.hpp @@ -28,6 +28,18 @@ namespace mstch { flag m_flag; }; + template<> inline + std::string render_section::operator()(const lambda& lam) const { + std::string section_str; + for(auto& token: section) + section_str += token.raw(); + return lam(section_str, [this](const std::string& str) { + std::cout << str << std::endl; + std::cout << ctx.render(template_type{str}) << std::endl; + return ctx.render(template_type{str}); + }); + } + template<> inline std::string render_section::operator()(const array& arr) const { std::string out; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 1ea0291..9ead276 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,4 +1,4 @@ -find_package(Boost 1.54 COMPONENTS program_options REQUIRED) +find_package(Boost 1.46 COMPONENTS program_options REQUIRED) include_directories( ${CMAKE_CURRENT_BINARY_DIR} diff --git a/test/data/nested_higher_order_sections.hpp b/test/data/nested_higher_order_sections.hpp index 27126f9..538e708 100644 --- a/test/data/nested_higher_order_sections.hpp +++ b/test/data/nested_higher_order_sections.hpp @@ -8,10 +8,9 @@ public: } mstch::node bold() { - return std::string{""}; - /*return [](const std::string& text, mstch::renderer render) { + return mstch::lambda{[](const std::string& text, mstch::renderer render) { return std::string{""} + render(text) + std::string{""}; - };*/ + }}; }; mstch::node person() {