diff --git a/src/render_context.cpp b/src/render_context.cpp index 60a8ea7..6036ece 100644 --- a/src/render_context.cpp +++ b/src/render_context.cpp @@ -61,8 +61,8 @@ void render_context::tokenize(const std::string& t, std::vector& toks) { 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]) { + if (pstate == parse_state::start) { + if (*it == delim_start[0]) { pstate = parse_state::in_del_start; tok_end = it; del_pos = 1; @@ -96,7 +96,8 @@ void render_context::tokenize(const std::string& t, std::vector& toks) { 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, it + 1}}); + toks.push_back({true, false, false, + {tok_end +delim_start.size(), it - delim_end.size() +1}}); ws_only = true; tok_start = it + 1; } else { @@ -110,15 +111,15 @@ void render_context::tokenize(const std::string& t, std::vector& toks) { void render_context::strip_whitespace(std::vector& tokens) { auto line_begin = tokens.begin(); bool has_tag = false, non_space = false; - for(auto it = tokens.begin(); it != tokens.end(); ++it) { + for (auto it = tokens.begin(); it != tokens.end(); ++it) { auto type = (*it).token_type(); - if(type != token::type::text && type != token::type::variable && + if (type != token::type::text && type != token::type::variable && type != token::type::unescaped_variable) has_tag = true; - else if(!(*it).is_ws_only()) + else if (!(*it).is_ws_only()) non_space = true; - if((*it).is_eol()) { - if(has_tag && !non_space) + if ((*it).is_eol()) { + if (has_tag && !non_space) for (auto line_it = line_begin; line_it != it + 1; ++line_it) if ((*line_it).is_ws_only()) (*line_it).mark(); @@ -126,7 +127,7 @@ void render_context::strip_whitespace(std::vector& tokens) { line_begin = it + 1; } } - for(auto it = tokens.begin(); it != tokens.end();) + for (auto it = tokens.begin(); it != tokens.end();) ((*it).is_marked())?(it = tokens.erase(it)):(++it); } @@ -139,7 +140,7 @@ std::string render_context::render(const std::string& tmplt) { std::string render_context::render(const std::vector& tokens) { std::string output; - for(auto& token: tokens) + for (auto& token: tokens) output += state.top()->render(*this, token); return output; } diff --git a/src/state/in_section.cpp b/src/state/in_section.cpp index d86b5ae..12af20a 100644 --- a/src/state/in_section.cpp +++ b/src/state/in_section.cpp @@ -14,7 +14,7 @@ std::string state::in_section::render(render_context& ctx, const token& token) { switch(token.token_type()) { case token::type::section_close: if(token.content() == section_name && skipped_openings == 0) { - auto section_node = ctx.get_node(section_name); + auto& section_node = ctx.get_node(section_name); std::string out; if (!boost::apply_visitor(visitor::is_node_empty(), section_node)) out = boost::apply_visitor( diff --git a/src/state/outside_section.cpp b/src/state/outside_section.cpp index 31f2780..7d51084 100644 --- a/src/state/outside_section.cpp +++ b/src/state/outside_section.cpp @@ -26,7 +26,7 @@ std::string state::outside_section::render( } case token::type::comment: break; case token::type::text: - return token.raw(); + return token.content(); case token::type::partial: return ctx.render_partial(token.content()); case token::type::section_close: break; diff --git a/src/token.cpp b/src/token.cpp index cb6f974..409369d 100644 --- a/src/token.cpp +++ b/src/token.cpp @@ -1,36 +1,48 @@ #include "token.hpp" -#include -#include using namespace mstch; -std::tuple token::token_info(const std::string& inside) { - switch (inside.at(0)) { - case '>': return std::make_tuple(1, 0, type::partial); - case '^': return std::make_tuple(1, 0, type::inverted_section_open); - case '/': return std::make_tuple(1, 0, type::section_close); - case '&': return std::make_tuple(1, 0, type::unescaped_variable); - case '#': return std::make_tuple(1, 0, type::section_open); - case '!': return std::make_tuple(1, 0, type::comment); - case '{': - if (inside.at(inside.size() - 1) == '}') - return std::make_tuple(1, 1, type::unescaped_variable); - default: return std::make_tuple(0, 0, type::variable); +token::type token::token_info(char c) { + switch (c) { + case '>': return type::partial; + case '^': return type::inverted_section_open; + case '/': return type::section_close; + case '&': return type::unescaped_variable; + case '#': return type::section_open; + case '!': return type::comment; + default: return type::variable; } } token::token(bool is_tag, bool eol, bool ws_only, const std::string& raw_val): - raw_val(raw_val), eol(eol), ws_only(ws_only), marked(false) + eol(eol), ws_only(ws_only), marked(false) { if(is_tag) { - std::string inside{raw_val.substr(2, raw_val.size() - 4)}; - boost::trim(inside); - if (inside.size() > 0) { - int lpad, rpad; - std::tie(lpad, rpad, type_val) = token_info(inside); - content_val = inside.substr(lpad, inside.size() - lpad - rpad); - boost::trim(content_val); + auto content_begin = raw_val.begin(), content_end = raw_val.end(); + parse_state state = parse_state::prews; + if(*content_begin == '{' && *(content_end - 1) == '}') { + state = parse_state::postws; + type_val = type::unescaped_variable; + ++content_begin; + --content_end; } + for(auto it = content_begin; it != content_end;) { + if(state == parse_state::prews && *it != ' ') { + state = parse_state::postws; + if((type_val = token_info(*it++)) == type::variable) { + state = parse_state::content; + content_begin = it -1; + } + } else if(state == parse_state::postws && *it != ' ') { + content_begin = it++; + state = parse_state::content; + } else if(state == parse_state::content && *it == ' ') { + content_end = it; + } else { + ++it; + } + } + content_val = {content_begin, content_end}; } else { type_val = type::text; content_val = raw_val; diff --git a/src/token.hpp b/src/token.hpp index 2e3e6a5..2e5bdd1 100644 --- a/src/token.hpp +++ b/src/token.hpp @@ -13,19 +13,18 @@ namespace mstch { token(bool is_tag, bool eol, bool ws_only, const std::string& raw_val); type token_type() const { return type_val; }; const std::string& content() const { return content_val; }; - const std::string& raw() const { return raw_val; }; bool is_eol() const { return eol; } bool is_ws_only() const { return ws_only; } bool is_marked() const { return marked; } void mark() { marked = true; }; private: + enum class parse_state { prews, postws, content }; type type_val; std::string content_val; - std::string raw_val; bool eol; bool ws_only; bool marked; - std::tuple token_info(const std::string& inside); + type token_info(char c); }; }