reformat
This commit is contained in:
parent
29980e299c
commit
f4dd438fcc
@ -4,6 +4,6 @@ option (WITH_UNIT_TESTS "enable building unit test executable" OFF)
|
|||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -O3")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -O3")
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
if(WITH_UNIT_TESTS)
|
if(WITH_UNIT_TESTS)
|
||||||
enable_testing()
|
enable_testing()
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
endif()
|
endif()
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
find_package(Boost 1.54 REQUIRED)
|
find_package(Boost 1.54 REQUIRED)
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
${CMAKE_SOURCE_DIR}/include
|
${CMAKE_SOURCE_DIR}/include
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
${Boost_INCLUDE_DIR})
|
${Boost_INCLUDE_DIR})
|
||||||
|
|
||||||
set(SRC
|
set(SRC
|
||||||
state/in_section.cpp
|
state/in_section.cpp
|
||||||
state/outside_section.cpp
|
state/outside_section.cpp
|
||||||
mstch.cpp
|
mstch.cpp
|
||||||
render_context.cpp
|
render_context.cpp
|
||||||
template_type.cpp
|
template_type.cpp
|
||||||
token.cpp
|
token.cpp
|
||||||
utils.cpp)
|
utils.cpp)
|
||||||
|
|
||||||
add_library(mstch STATIC ${SRC})
|
add_library(mstch STATIC ${SRC})
|
||||||
|
@ -7,12 +7,12 @@
|
|||||||
using namespace mstch;
|
using namespace mstch;
|
||||||
|
|
||||||
std::string mstch::render(
|
std::string mstch::render(
|
||||||
const std::string& tmplt,
|
const std::string& tmplt,
|
||||||
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_templts;
|
||||||
for(auto& partial: partials)
|
for (auto& partial: partials)
|
||||||
partial_templts.insert({partial.first, {partial.second}});
|
partial_templts.insert({partial.first, {partial.second}});
|
||||||
return render_context(root, partial_templts).render(tmplt);
|
return render_context(root, partial_templts).render(tmplt);
|
||||||
}
|
}
|
||||||
|
@ -5,62 +5,63 @@
|
|||||||
#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;
|
||||||
|
|
||||||
render_context::push::push(render_context& context, const mstch::node& node):
|
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<state::render_state>(
|
||||||
new state::outside_section));
|
new state::outside_section));
|
||||||
}
|
}
|
||||||
|
|
||||||
render_context::push::~push() {
|
render_context::push::~push() {
|
||||||
context.nodes.pop_front();
|
context.nodes.pop_front();
|
||||||
context.state.pop();
|
context.state.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string render_context::push::render(const template_type& templt) {
|
std::string render_context::push::render(const template_type& templt) {
|
||||||
return context.render(templt);
|
return context.render(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<state::render_state>(
|
||||||
new state::outside_section));
|
new state::outside_section));
|
||||||
}
|
}
|
||||||
|
|
||||||
const mstch::node& render_context::find_node(
|
const mstch::node& render_context::find_node(
|
||||||
const std::string& token,
|
const std::string& token,
|
||||||
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& i: current_nodes)
|
for (auto& node: current_nodes)
|
||||||
if (boost::apply_visitor(visitor::has_token(token), i))
|
if (visit(has_token(token), node))
|
||||||
return boost::apply_visitor(visitor::get_token(token, i), i);
|
return visit(get_token(token, node), node);
|
||||||
return null_node;
|
return null_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mstch::node& render_context::get_node(const std::string& token) {
|
const mstch::node& render_context::get_node(const std::string& token) {
|
||||||
return find_node(token, nodes);
|
return find_node(token, nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string render_context::render(const template_type& templt) {
|
std::string render_context::render(const template_type& templt) {
|
||||||
std::string output;
|
std::string output;
|
||||||
for (auto& token: templt)
|
for (auto& token: templt)
|
||||||
output += state.top()->render(*this, token);
|
output += state.top()->render(*this, token);
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string render_context::render_partial(const std::string& partial_name) {
|
std::string render_context::render_partial(const std::string& partial_name) {
|
||||||
return (partials.count(partial_name))?render(partials.at(partial_name)):"";
|
return (partials.count(partial_name))?render(partials.at(partial_name)):"";
|
||||||
}
|
}
|
||||||
|
@ -10,34 +10,38 @@
|
|||||||
#include "template_type.hpp"
|
#include "template_type.hpp"
|
||||||
|
|
||||||
namespace mstch {
|
namespace mstch {
|
||||||
class render_context {
|
|
||||||
public:
|
class render_context {
|
||||||
class push {
|
public:
|
||||||
public:
|
class push {
|
||||||
push(render_context& context, const mstch::node& node = {});
|
public:
|
||||||
~push();
|
push(render_context& context, const mstch::node& node = {});
|
||||||
std::string render(const template_type& templt);
|
~push();
|
||||||
private:
|
std::string render(const template_type& templt);
|
||||||
render_context& context;
|
private:
|
||||||
};
|
render_context& context;
|
||||||
render_context(
|
};
|
||||||
const mstch::node& node,
|
|
||||||
const std::map<std::string,template_type>& partials);
|
render_context(
|
||||||
const mstch::node& get_node(const std::string& token);
|
const mstch::node& node,
|
||||||
std::string render(const template_type& templt);
|
const std::map<std::string, template_type>& partials);
|
||||||
std::string render_partial(const std::string& partial_name);
|
const mstch::node& get_node(const std::string& token);
|
||||||
template<class T, class... Args>
|
std::string render(const template_type& templt);
|
||||||
void set_state(Args&&... args) {
|
std::string render_partial(const std::string& partial_name);
|
||||||
state.top() = std::unique_ptr<state::render_state>(
|
template<class T, class... Args>
|
||||||
new T(std::forward<Args>(args)...));
|
void set_state(Args&& ... args) {
|
||||||
}
|
state.top() = std::unique_ptr<state::render_state>(
|
||||||
private:
|
new T(std::forward<Args>(args)...));
|
||||||
static const mstch::node null_node;
|
}
|
||||||
const mstch::node& find_node(
|
|
||||||
const std::string& token,
|
private:
|
||||||
const std::deque<node>& current_nodes);
|
static const mstch::node null_node;
|
||||||
const std::map<std::string,template_type>& partials;
|
const mstch::node& find_node(
|
||||||
std::deque<mstch::node> nodes;
|
const std::string& token,
|
||||||
std::stack<std::unique_ptr<state::render_state>> state;
|
const std::deque<node>& current_nodes);
|
||||||
};
|
const std::map<std::string, template_type>& partials;
|
||||||
|
std::deque<mstch::node> nodes;
|
||||||
|
std::stack<std::unique_ptr<state::render_state>> state;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,10 @@
|
|||||||
#include "outside_section.hpp"
|
#include "outside_section.hpp"
|
||||||
#include "visitor/is_node_empty.hpp"
|
#include "visitor/is_node_empty.hpp"
|
||||||
#include "visitor/render_section.hpp"
|
#include "visitor/render_section.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):
|
state::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)
|
||||||
@ -11,21 +13,20 @@ state::in_section::in_section(type type, const std::string& section_name):
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string state::in_section::render(render_context& ctx, const token& token) {
|
std::string state::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& sn = ctx.get_node(section_name);
|
auto& node = ctx.get_node(section_name);
|
||||||
std::string out;
|
std::string out;
|
||||||
if(m_type == type::normal &&
|
if (m_type == type::normal && !visit(is_node_empty(), node))
|
||||||
!boost::apply_visitor(visitor::is_node_empty(), sn))
|
out = visit(render_section(ctx, section), node);
|
||||||
out = boost::apply_visitor(visitor::render_section(ctx, section), sn);
|
else if (m_type == type::inverted && visit(is_node_empty(), node))
|
||||||
else if(m_type == type::inverted &&
|
|
||||||
boost::apply_visitor(visitor::is_node_empty(), sn))
|
|
||||||
out = render_context::push(ctx).render(section);
|
out = render_context::push(ctx).render(section);
|
||||||
ctx.set_state<outside_section>();
|
ctx.set_state<outside_section>();
|
||||||
return out;
|
return out;
|
||||||
} else
|
} else {
|
||||||
skipped_openings--;
|
skipped_openings--;
|
||||||
else if(token.token_type() == token::type::inverted_section_open ||
|
}
|
||||||
|
else if (token.token_type() == token::type::inverted_section_open ||
|
||||||
token.token_type() == token::type::section_open)
|
token.token_type() == token::type::section_open)
|
||||||
skipped_openings++;
|
skipped_openings++;
|
||||||
section << token;
|
section << token;
|
||||||
|
@ -1,23 +1,28 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "render_state.hpp"
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "render_state.hpp"
|
||||||
#include "template_type.hpp"
|
#include "template_type.hpp"
|
||||||
|
|
||||||
namespace mstch {
|
namespace mstch {
|
||||||
namespace state {
|
namespace state {
|
||||||
class in_section: public render_state {
|
|
||||||
public:
|
class in_section: public render_state {
|
||||||
enum class type { inverted, normal };
|
public:
|
||||||
in_section(type type, const std::string& section_name);
|
enum class type {
|
||||||
std::string render(
|
inverted, normal
|
||||||
render_context& context, const token& token) override;
|
};
|
||||||
private:
|
in_section(type type, const std::string §ion_name);
|
||||||
const type m_type;
|
std::string render(render_context &context, const token &token) override;
|
||||||
const std::string section_name;
|
|
||||||
template_type section;
|
private:
|
||||||
int skipped_openings;
|
const type m_type;
|
||||||
};
|
const std::string section_name;
|
||||||
}
|
template_type section;
|
||||||
|
int skipped_openings;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,33 +1,34 @@
|
|||||||
#include "visitor/render_node.hpp"
|
|
||||||
#include "outside_section.hpp"
|
#include "outside_section.hpp"
|
||||||
|
|
||||||
|
#include "visitor/render_node.hpp"
|
||||||
#include "in_section.hpp"
|
#include "in_section.hpp"
|
||||||
#include "render_context.hpp"
|
#include "render_context.hpp"
|
||||||
|
#include "utils.hpp"
|
||||||
|
|
||||||
using namespace mstch;
|
using namespace mstch;
|
||||||
|
using namespace mstch::visitor;
|
||||||
|
|
||||||
std::string state::outside_section::render(
|
std::string state::outside_section::render(
|
||||||
render_context& ctx, const token& token)
|
render_context& ctx, const token& token)
|
||||||
{
|
{
|
||||||
switch(token.token_type()) {
|
using flag = render_node::flag;
|
||||||
|
switch (token.token_type()) {
|
||||||
case token::type::section_open:
|
case token::type::section_open:
|
||||||
ctx.set_state<in_section>(in_section::type::normal, token.name());
|
ctx.set_state<in_section>(in_section::type::normal, token.name());
|
||||||
break;
|
break;
|
||||||
case token::type::inverted_section_open:
|
case token::type::inverted_section_open:
|
||||||
ctx.set_state<in_section>(in_section::type::inverted, token.name());
|
ctx.set_state<in_section>(in_section::type::inverted, token.name());
|
||||||
break;
|
break;
|
||||||
case token::type::variable:
|
case token::type::variable:
|
||||||
return boost::apply_visitor(
|
return visit(render_node(flag::escape_html), ctx.get_node(token.name()));
|
||||||
visitor::render_node(visitor::render_node::flag::escape_html),
|
|
||||||
ctx.get_node(token.name()));
|
|
||||||
case token::type::unescaped_variable:
|
case token::type::unescaped_variable:
|
||||||
return boost::apply_visitor(
|
return visit(render_node(flag::none), ctx.get_node(token.name()));
|
||||||
visitor::render_node(visitor::render_node::flag::none),
|
|
||||||
ctx.get_node(token.name()));
|
|
||||||
case token::type::text:
|
case token::type::text:
|
||||||
return token.raw();
|
return token.raw();
|
||||||
case token::type::partial:
|
case token::type::partial:
|
||||||
return ctx.render_partial(token.name());
|
return ctx.render_partial(token.name());
|
||||||
default: break;
|
default:
|
||||||
}
|
break;
|
||||||
return "";
|
}
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,12 @@
|
|||||||
#include "render_state.hpp"
|
#include "render_state.hpp"
|
||||||
|
|
||||||
namespace mstch {
|
namespace mstch {
|
||||||
namespace state {
|
namespace state {
|
||||||
class outside_section: public render_state {
|
|
||||||
public:
|
class outside_section: public render_state {
|
||||||
std::string render(
|
public:
|
||||||
render_context& context, const token& token) override;
|
std::string render(render_context& context, const token& token) override;
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,19 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "token.hpp"
|
#include "token.hpp"
|
||||||
|
|
||||||
namespace mstch {
|
namespace mstch {
|
||||||
class render_context;
|
|
||||||
namespace state {
|
class render_context;
|
||||||
class render_state {
|
|
||||||
public:
|
namespace state {
|
||||||
virtual std::string render(
|
|
||||||
render_context& context, const token& token) = 0;
|
class render_state {
|
||||||
};
|
public:
|
||||||
}
|
virtual std::string render(render_context& context, const token& token) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,82 +3,82 @@
|
|||||||
using namespace mstch;
|
using namespace mstch;
|
||||||
|
|
||||||
template_type::template_type(const std::string& str) {
|
template_type::template_type(const std::string& str) {
|
||||||
tokenize(str);
|
tokenize(str);
|
||||||
strip_whitespace();
|
strip_whitespace();
|
||||||
}
|
}
|
||||||
|
|
||||||
void template_type::tokenize(const std::string& t) {
|
void template_type::tokenize(const std::string& t) {
|
||||||
std::string delim_start{"{{"};
|
std::string delim_start{"{{"};
|
||||||
std::string delim_end{"}}"};
|
std::string delim_end{"}}"};
|
||||||
std::string::const_iterator tok_end, tok_start = t.begin();
|
std::string::const_iterator tok_end, tok_start = t.begin();
|
||||||
parse_state pstate = parse_state::start;
|
parse_state pstate = parse_state::start;
|
||||||
unsigned int del_pos = 0;
|
unsigned int del_pos = 0;
|
||||||
for (std::string::const_iterator it = t.begin(); it != t.end(); ++it) {
|
for (std::string::const_iterator it = t.begin(); it != t.end(); ++it) {
|
||||||
if (pstate == parse_state::start) {
|
if (pstate == parse_state::start) {
|
||||||
if (*it == delim_start[0]) {
|
if (*it == delim_start[0]) {
|
||||||
pstate = parse_state::in_del_start;
|
pstate = parse_state::in_del_start;
|
||||||
tok_end = it;
|
tok_end = it;
|
||||||
del_pos = 1;
|
del_pos = 1;
|
||||||
} else if(*it == '\n') {
|
} else if (*it == '\n') {
|
||||||
tokens.push_back({{tok_start, it + 1}});
|
tokens.push_back({{tok_start, it + 1}});
|
||||||
tok_start = it + 1;
|
tok_start = it + 1;
|
||||||
}
|
}
|
||||||
} else if(pstate == parse_state::in_del_start) {
|
} else if (pstate == parse_state::in_del_start) {
|
||||||
if (*it == delim_start[del_pos] && ++del_pos == delim_start.size())
|
if (*it == delim_start[del_pos] && ++del_pos == delim_start.size())
|
||||||
pstate = parse_state::in_del;
|
pstate = parse_state::in_del;
|
||||||
else
|
else
|
||||||
pstate = parse_state::start;
|
pstate = parse_state::start;
|
||||||
} else if(pstate == parse_state::in_del) {
|
} else if (pstate == parse_state::in_del) {
|
||||||
if (*it == '{')
|
if (*it == '{')
|
||||||
pstate = parse_state::in_esccontent;
|
pstate = parse_state::in_esccontent;
|
||||||
else if (*it == delim_end[0] && (del_pos = 1))
|
else if (*it == delim_end[0] && (del_pos = 1))
|
||||||
pstate = parse_state::in_del_end;
|
pstate = parse_state::in_del_end;
|
||||||
else
|
else
|
||||||
pstate = parse_state::in_content;
|
pstate = parse_state::in_content;
|
||||||
} else if(pstate == parse_state::in_esccontent && *it == '}') {
|
} else if (pstate == parse_state::in_esccontent && *it == '}') {
|
||||||
pstate = parse_state::in_content;
|
pstate = parse_state::in_content;
|
||||||
} else if(pstate == parse_state::in_content && *it == delim_end[0]) {
|
} else if (pstate == parse_state::in_content && *it == delim_end[0]) {
|
||||||
pstate = parse_state::in_del_end;
|
pstate = parse_state::in_del_end;
|
||||||
del_pos = 1;
|
del_pos = 1;
|
||||||
} else if(pstate == parse_state::in_del_end) {
|
} else if (pstate == parse_state::in_del_end) {
|
||||||
if (*it == delim_end[del_pos] && ++del_pos == delim_end.size()) {
|
if (*it == delim_end[del_pos] && ++del_pos == delim_end.size()) {
|
||||||
pstate = parse_state::start;
|
pstate = parse_state::start;
|
||||||
tokens.push_back({{tok_start, tok_end}});
|
tokens.push_back({{tok_start, tok_end}});
|
||||||
tokens.push_back(
|
tokens.push_back(
|
||||||
{{tok_end, it + 1},
|
{{tok_end, it + 1},
|
||||||
delim_start.size(),
|
delim_start.size(),
|
||||||
delim_end.size()});
|
delim_end.size()});
|
||||||
tok_start = it + 1;
|
tok_start = it + 1;
|
||||||
} else {
|
} else {
|
||||||
pstate = parse_state::start;
|
pstate = parse_state::start;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
tokens.push_back({{tok_start, t.end()}});
|
}
|
||||||
|
tokens.push_back({{tok_start, t.end()}});
|
||||||
}
|
}
|
||||||
|
|
||||||
void template_type::strip_whitespace() {
|
void template_type::strip_whitespace() {
|
||||||
auto line_begin = tokens.begin();
|
auto line_begin = tokens.begin();
|
||||||
bool has_tag = false, non_space = false;
|
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();
|
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)
|
type != token::type::unescaped_variable)
|
||||||
has_tag = true;
|
has_tag = true;
|
||||||
else if (!(*it).ws_only())
|
else if (!(*it).ws_only())
|
||||||
non_space = true;
|
non_space = true;
|
||||||
if ((*it).eol()) {
|
if ((*it).eol()) {
|
||||||
if (has_tag && !non_space) {
|
if (has_tag && !non_space) {
|
||||||
auto line_it = line_begin;
|
auto line_it = line_begin;
|
||||||
for (; !(*line_it).eol(); ++line_it)
|
for (; !(*line_it).eol(); ++line_it)
|
||||||
if ((*line_it).ws_only())
|
if ((*line_it).ws_only())
|
||||||
line_it = tokens.erase(line_it);
|
line_it = tokens.erase(line_it);
|
||||||
if ((*line_it).ws_only())
|
if ((*line_it).ws_only())
|
||||||
line_it = tokens.erase(line_it);
|
line_it = tokens.erase(line_it);
|
||||||
it = line_it - 1;
|
it = line_it - 1;
|
||||||
}
|
}
|
||||||
non_space = has_tag = false;
|
non_space = has_tag = false;
|
||||||
line_begin = it + 1;
|
line_begin = it + 1;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,19 +6,22 @@
|
|||||||
#include "token.hpp"
|
#include "token.hpp"
|
||||||
|
|
||||||
namespace mstch {
|
namespace mstch {
|
||||||
class template_type {
|
|
||||||
public:
|
class template_type {
|
||||||
template_type() = default;
|
public:
|
||||||
template_type(const std::string& str);
|
template_type() = default;
|
||||||
std::vector<token>::const_iterator begin() const{return tokens.begin();}
|
template_type(const std::string& str);
|
||||||
std::vector<token>::const_iterator end() const{return tokens.end();}
|
std::vector<token>::const_iterator begin() const { return tokens.begin(); }
|
||||||
void operator<<(const token& token) { tokens.push_back(token); }
|
std::vector<token>::const_iterator end() const { return tokens.end(); }
|
||||||
private:
|
void operator<<(const token& token) { tokens.push_back(token); }
|
||||||
enum class parse_state {
|
|
||||||
start, in_del_start, in_del, in_content, in_esccontent, in_del_end
|
private:
|
||||||
};
|
enum class parse_state {
|
||||||
void tokenize(const std::string& str);
|
start, in_del_start, in_del, in_content, in_esccontent, in_del_end
|
||||||
void strip_whitespace();
|
};
|
||||||
std::vector<token> tokens;
|
void tokenize(const std::string& str);
|
||||||
};
|
void strip_whitespace();
|
||||||
|
std::vector<token> tokens;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
using namespace mstch;
|
using namespace mstch;
|
||||||
|
|
||||||
token::type token::token_info(char c) {
|
token::type token::token_info(char c) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '>': return type::partial;
|
case '>': return type::partial;
|
||||||
case '^': return type::inverted_section_open;
|
case '^': return type::inverted_section_open;
|
||||||
case '/': return type::section_close;
|
case '/': return type::section_close;
|
||||||
@ -12,27 +12,27 @@ token::type token::token_info(char c) {
|
|||||||
case '#': return type::section_open;
|
case '#': return type::section_open;
|
||||||
case '!': return type::comment;
|
case '!': return type::comment;
|
||||||
default: return type::variable;
|
default: return type::variable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
token::token(const std::string& str, std::size_t left, std::size_t right):
|
token::token(const std::string& str, std::size_t left, std::size_t right):
|
||||||
m_raw(str), m_eol(false), m_ws_only(false)
|
m_raw(str), m_eol(false), m_ws_only(false)
|
||||||
{
|
{
|
||||||
if(left != 0 && right != 0) {
|
if (left != 0 && right != 0) {
|
||||||
if(str[left] == '{' && str[str.size() - right - 1] == '}') {
|
if (str[left] == '{' && str[str.size() - right - 1] == '}') {
|
||||||
m_type = type::unescaped_variable;
|
m_type = type::unescaped_variable;
|
||||||
m_name = {first_not_ws(str.begin() + left + 1, str.end() - right),
|
m_name = {first_not_ws(str.begin() + left + 1, str.end() - right),
|
||||||
first_not_ws(str.rbegin() + 1 + right, str.rend() - left) + 1};
|
first_not_ws(str.rbegin() + 1 + right, str.rend() - left) + 1};
|
||||||
} else {
|
|
||||||
auto first = first_not_ws(str.begin() + left, str.end() - right);
|
|
||||||
m_type = token_info(*first);
|
|
||||||
if(m_type != type::variable)
|
|
||||||
first = first_not_ws(first + 1, str.end() - right);
|
|
||||||
m_name = {first, first_not_ws(str.rbegin() + right, str.rend() - left) + 1};
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
m_type = type::text;
|
auto c = first_not_ws(str.begin() + left, str.end() - right);
|
||||||
m_eol = (str.size() > 0 && str[str.size() - 1] == '\n');
|
m_type = token_info(*c);
|
||||||
m_ws_only = (str.find_first_not_of(" \n\t") == std::string::npos);
|
if (m_type != type::variable)
|
||||||
|
c = first_not_ws(c + 1, str.end() - right);
|
||||||
|
m_name = {c, first_not_ws(str.rbegin() + right, str.rend() - left) + 1};
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
m_type = type::text;
|
||||||
|
m_eol = (str.size() > 0 && str[str.size() - 1] == '\n');
|
||||||
|
m_ws_only = (str.find_first_not_of(" \n\t") == std::string::npos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,24 +3,27 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace mstch {
|
namespace mstch {
|
||||||
class token {
|
|
||||||
public:
|
class token {
|
||||||
enum class type {
|
public:
|
||||||
text, variable, section_open, section_close, inverted_section_open,
|
enum class type {
|
||||||
unescaped_variable, comment, partial
|
text, variable, section_open, section_close, inverted_section_open,
|
||||||
};
|
unescaped_variable, comment, partial
|
||||||
token(const std::string& str, std::size_t left = 0, std::size_t right = 0);
|
};
|
||||||
type token_type() const { return m_type; };
|
token(const std::string& str, std::size_t left = 0, std::size_t right = 0);
|
||||||
const std::string& raw() const { return m_raw; };
|
type token_type() const { return m_type; };
|
||||||
const std::string& name() const { return m_name; };
|
const std::string& raw() const { return m_raw; };
|
||||||
bool eol() const { return m_eol; }
|
const std::string& name() const { return m_name; };
|
||||||
bool ws_only() const { return m_ws_only; }
|
bool eol() const { return m_eol; }
|
||||||
private:
|
bool ws_only() const { return m_ws_only; }
|
||||||
type m_type;
|
|
||||||
std::string m_name;
|
private:
|
||||||
std::string m_raw;
|
type m_type;
|
||||||
bool m_eol;
|
std::string m_name;
|
||||||
bool m_ws_only;
|
std::string m_raw;
|
||||||
type token_info(char c);
|
bool m_eol;
|
||||||
};
|
bool m_ws_only;
|
||||||
|
type token_info(char c);
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,23 +3,23 @@
|
|||||||
#include <boost/algorithm/string/replace.hpp>
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
|
|
||||||
mstch::citer mstch::first_not_ws(mstch::citer begin, mstch::citer end) {
|
mstch::citer mstch::first_not_ws(mstch::citer begin, mstch::citer end) {
|
||||||
for(auto it = begin; it != end; ++it)
|
for (auto it = begin; it != end; ++it)
|
||||||
if(*it != ' ') return it;
|
if (*it != ' ') return it;
|
||||||
return end;
|
return end;
|
||||||
}
|
}
|
||||||
|
|
||||||
mstch::citer mstch::first_not_ws(mstch::criter begin, mstch::criter end) {
|
mstch::citer mstch::first_not_ws(mstch::criter begin, mstch::criter end) {
|
||||||
for(auto rit = begin; rit != end; ++rit)
|
for (auto rit = begin; rit != end; ++rit)
|
||||||
if(*rit != ' ') return --(rit.base());
|
if (*rit != ' ') return --(rit.base());
|
||||||
return --(end.base());
|
return --(end.base());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string mstch::html_escape(std::string str) {
|
std::string mstch::html_escape(std::string str) {
|
||||||
boost::replace_all(str, "&", "&");
|
boost::replace_all(str, "&", "&");
|
||||||
boost::replace_all(str, "'", "'");
|
boost::replace_all(str, "'", "'");
|
||||||
boost::replace_all(str, "\"", """);
|
boost::replace_all(str, "\"", """);
|
||||||
boost::replace_all(str, "<", "<");
|
boost::replace_all(str, "<", "<");
|
||||||
boost::replace_all(str, ">", ">");
|
boost::replace_all(str, ">", ">");
|
||||||
boost::replace_all(str, "/", "/");
|
boost::replace_all(str, "/", "/");
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,22 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <boost/variant/apply_visitor.hpp>
|
||||||
|
|
||||||
namespace mstch {
|
namespace mstch {
|
||||||
using citer = std::string::const_iterator;
|
|
||||||
using criter = std::string::const_reverse_iterator;
|
using citer = std::string::const_iterator;
|
||||||
citer first_not_ws(citer begin, citer end);
|
using criter = std::string::const_reverse_iterator;
|
||||||
citer first_not_ws(criter begin, criter end);
|
|
||||||
std::string html_escape(std::string str);
|
citer first_not_ws(citer begin, citer end);
|
||||||
|
citer first_not_ws(criter begin, criter end);
|
||||||
|
std::string html_escape(std::string str);
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
|
auto visit(Args&& ... args) -> decltype(boost::apply_visitor(
|
||||||
|
std::forward<Args>(args)...))
|
||||||
|
{
|
||||||
|
return boost::apply_visitor(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <boost/variant/static_visitor.hpp>
|
#include <boost/variant/static_visitor.hpp>
|
||||||
#include <boost/blank.hpp>
|
#include <boost/blank.hpp>
|
||||||
|
|
||||||
#include "mstch/mstch.hpp"
|
#include "mstch/mstch.hpp"
|
||||||
|
|
||||||
namespace mstch {
|
namespace mstch {
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <boost/variant/static_visitor.hpp>
|
#include <boost/variant/static_visitor.hpp>
|
||||||
#include <boost/blank.hpp>
|
#include <boost/blank.hpp>
|
||||||
|
|
||||||
#include "mstch/mstch.hpp"
|
#include "mstch/mstch.hpp"
|
||||||
|
|
||||||
namespace mstch {
|
namespace mstch {
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "render_context.hpp"
|
#include "render_context.hpp"
|
||||||
#include "mstch/mstch.hpp"
|
#include "mstch/mstch.hpp"
|
||||||
|
#include "utils.hpp"
|
||||||
|
|
||||||
namespace mstch {
|
namespace mstch {
|
||||||
namespace visitor {
|
namespace visitor {
|
||||||
@ -49,8 +50,7 @@ inline std::string render_section::operator()<array>(const array& array) const {
|
|||||||
out += render_context::push(ctx, array).render(section);
|
out += render_context::push(ctx, array).render(section);
|
||||||
else
|
else
|
||||||
for (auto& item: array)
|
for (auto& item: array)
|
||||||
out += boost::apply_visitor(
|
out += visit(render_section(ctx, section, flag::keep_array), item);
|
||||||
render_section(ctx, section, flag::keep_array), item);
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,44 +1,43 @@
|
|||||||
find_package(Boost 1.54 COMPONENTS program_options REQUIRED)
|
find_package(Boost 1.54 COMPONENTS program_options REQUIRED)
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
${CMAKE_CURRENT_BINARY_DIR}
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
${CMAKE_SOURCE_DIR}/include
|
${CMAKE_SOURCE_DIR}/include
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
${Boost_INCLUDE_DIR})
|
${Boost_INCLUDE_DIR})
|
||||||
|
|
||||||
add_executable(benchmark benchmark_main.cpp)
|
add_executable(benchmark benchmark_main.cpp)
|
||||||
target_link_libraries(benchmark mstch)
|
target_link_libraries(benchmark mstch)
|
||||||
|
|
||||||
add_executable(filetoheader filetoheader.cpp)
|
add_executable(headerize headerize.cpp)
|
||||||
target_link_libraries(filetoheader ${Boost_PROGRAM_OPTIONS_LIBRARY})
|
target_link_libraries(headerize ${Boost_PROGRAM_OPTIONS_LIBRARY})
|
||||||
set(filetoheader_exe ${CMAKE_CURRENT_BINARY_DIR}/filetoheader${CMAKE_EXECUTABLE_SUFFIX})
|
set(headerize_exe ${CMAKE_CURRENT_BINARY_DIR}/headerize${CMAKE_EXECUTABLE_SUFFIX})
|
||||||
|
|
||||||
file(GLOB data_files RELATIVE
|
file(GLOB data_files RELATIVE
|
||||||
"${CMAKE_SOURCE_DIR}/test/data"
|
"${CMAKE_SOURCE_DIR}/test/data"
|
||||||
"${CMAKE_SOURCE_DIR}/test/data/*.hpp")
|
"${CMAKE_SOURCE_DIR}/test/data/*.hpp")
|
||||||
|
|
||||||
foreach(data_file ${data_files})
|
foreach(data_file ${data_files})
|
||||||
list(APPEND genargs "-C${data_file}")
|
list(APPEND genargs "-C${data_file}")
|
||||||
string(REGEX REPLACE "\\.hpp" "" test_name "${data_file}")
|
string(REGEX REPLACE "\\.hpp" "" test_name "${data_file}")
|
||||||
list(APPEND tests "${test_name}")
|
list(APPEND tests "${test_name}")
|
||||||
endforeach(data_file)
|
endforeach(data_file)
|
||||||
|
|
||||||
file(GLOB string_files RELATIVE
|
file(GLOB string_files RELATIVE
|
||||||
"${CMAKE_SOURCE_DIR}/test/data"
|
"${CMAKE_SOURCE_DIR}/test/data"
|
||||||
"${CMAKE_SOURCE_DIR}/test/data/*.mustache"
|
"${CMAKE_SOURCE_DIR}/test/data/*.mustache"
|
||||||
"${CMAKE_SOURCE_DIR}/test/data/*.txt"
|
"${CMAKE_SOURCE_DIR}/test/data/*.txt"
|
||||||
"${CMAKE_SOURCE_DIR}/test/data/*.partial"
|
"${CMAKE_SOURCE_DIR}/test/data/*.partial")
|
||||||
)
|
|
||||||
|
|
||||||
foreach(string_file ${string_files})
|
foreach(string_file ${string_files})
|
||||||
list(APPEND genargs "-S${string_file}")
|
list(APPEND genargs "-S${string_file}")
|
||||||
endforeach(string_file)
|
endforeach(string_file)
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/test_data.hpp
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/test_data.hpp
|
||||||
COMMAND ${filetoheader_exe} --output ${CMAKE_CURRENT_BINARY_DIR}/test_data.hpp --namespace mstchtest ${genargs}
|
COMMAND ${headerize_exe} --output ${CMAKE_CURRENT_BINARY_DIR}/test_data.hpp --namespace mstchtest ${genargs}
|
||||||
DEPENDS ${filetoheader_exe}
|
DEPENDS ${headerize_exe}
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/test/data/)
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/test/data/)
|
||||||
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/test_data.hpp PROPERTIES GENERATED TRUE)
|
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/test_data.hpp PROPERTIES GENERATED TRUE)
|
||||||
add_custom_target(test_data_hpp DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/test_data.hpp)
|
add_custom_target(test_data_hpp DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/test_data.hpp)
|
||||||
|
|
||||||
@ -47,5 +46,5 @@ target_link_libraries(mstch_test mstch)
|
|||||||
add_dependencies(mstch_test test_data_hpp)
|
add_dependencies(mstch_test test_data_hpp)
|
||||||
|
|
||||||
foreach(test ${tests})
|
foreach(test ${tests})
|
||||||
add_test(NAME ${test} COMMAND mstch_test ${test})
|
add_test(NAME ${test} COMMAND mstch_test ${test})
|
||||||
endforeach(test)
|
endforeach(test)
|
||||||
|
@ -3,40 +3,42 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
unsigned long current_msec() {
|
||||||
|
return std::chrono::system_clock::now().time_since_epoch() /
|
||||||
|
std::chrono::milliseconds(1);
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
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{
|
||||||
mstch::map{{"name", std::string{"Joe"}}, {"body", std::string{"Thanks for this post!"}}},
|
mstch::map{{"name", std::string{"Joe"}}, {"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{"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<int> times;
|
std::vector<unsigned long> times;
|
||||||
for(int j = 0; j < 10; j++) {
|
for (int j = 0; j < 10; j++) {
|
||||||
unsigned long start =
|
unsigned long start = current_msec();
|
||||||
std::chrono::system_clock::now().time_since_epoch() /
|
for (int i = 0; i < 5000; i++)
|
||||||
std::chrono::milliseconds(1);
|
mstch::render(comment_tmp, comment_view);
|
||||||
for(int i = 0; i < 5000; i++) {
|
times.push_back(current_msec() - start);
|
||||||
mstch::render(comment_tmp, comment_view);
|
}
|
||||||
}
|
|
||||||
times.push_back((std::chrono::system_clock::now().time_since_epoch() /
|
|
||||||
std::chrono::milliseconds(1)) - start);
|
|
||||||
}
|
|
||||||
|
|
||||||
float avg = 0;
|
float avg = 0;
|
||||||
for(int i: times) avg += i;
|
for (auto i: times)
|
||||||
avg /= times.size();
|
avg += i;
|
||||||
|
avg /= times.size();
|
||||||
|
|
||||||
std::cout << avg << std::endl;
|
std::cout << avg << std::endl;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,82 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
#include <boost/algorithm/string/replace.hpp>
|
|
||||||
#include <boost/program_options/options_description.hpp>
|
|
||||||
#include <boost/program_options/variables_map.hpp>
|
|
||||||
#include <boost/program_options/parsers.hpp>
|
|
||||||
|
|
||||||
void wrap_code(std::istream& input, std::ostream& output) {
|
|
||||||
std::string line;
|
|
||||||
while (std::getline(input, line)) {
|
|
||||||
output << line;
|
|
||||||
if(!input.eof()) output << std::endl;
|
|
||||||
}
|
|
||||||
output << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void wrap_string(std::istream& input, std::ostream& output, const std::string& variable_name) {
|
|
||||||
output << "const std::string " << variable_name << "{" << std::endl;;
|
|
||||||
std::string line;
|
|
||||||
while (std::getline(input, line)) {
|
|
||||||
boost::replace_all(line, "\\", "\\\\");
|
|
||||||
boost::replace_all(line, "\"", "\\\"");
|
|
||||||
output << " \"" << line;
|
|
||||||
if(!input.eof()) output << "\\n";
|
|
||||||
output << "\"" << std::endl;
|
|
||||||
}
|
|
||||||
output << "};" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
|
||||||
namespace po = boost::program_options;
|
|
||||||
|
|
||||||
po::options_description desc("Allowed options");
|
|
||||||
desc.add_options()
|
|
||||||
("help", "show help")
|
|
||||||
("output", po::value<std::string>(), "output file")
|
|
||||||
("namespace", po::value<std::string>(), "namespace to use")
|
|
||||||
("input-string,S", po::value<std::vector<std::string>>(), "files to parse as strings")
|
|
||||||
("input-code,C", po::value<std::vector<std::string>>(), "files to parse as code");
|
|
||||||
po::variables_map vm;
|
|
||||||
po::store(po::parse_command_line(argc, argv, desc), vm);
|
|
||||||
po::notify(vm);
|
|
||||||
|
|
||||||
if (vm.count("help")) {
|
|
||||||
std::cout << desc << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vm.count("output")) {
|
|
||||||
std::cout << "Output file not set" << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ofstream output(vm["output"].as<std::string>(), std::ios::out);
|
|
||||||
|
|
||||||
if(vm.count("namespace"))
|
|
||||||
output << "namespace " << vm["namespace"].as<std::string>() << " {" << std::endl;
|
|
||||||
|
|
||||||
if(vm.count("input-string")) {
|
|
||||||
for (auto &string_filename: vm["input-string"].as<std::vector<std::string>>()) {
|
|
||||||
std::ifstream input(string_filename, std::ios::in);
|
|
||||||
wrap_string(input, output, boost::replace_all_copy(string_filename, ".", "_"));
|
|
||||||
input.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(vm.count("input-code")) {
|
|
||||||
for(auto& data_filename: vm["input-code"].as<std::vector<std::string>>()) {
|
|
||||||
std::ifstream input(data_filename, std::ios::in);
|
|
||||||
wrap_code(input, output);
|
|
||||||
input.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(vm.count("namespace"))
|
|
||||||
output << "}" << std::endl;
|
|
||||||
|
|
||||||
output.close();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
89
test/headerize.cpp
Normal file
89
test/headerize.cpp
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
|
#include <boost/program_options/options_description.hpp>
|
||||||
|
#include <boost/program_options/variables_map.hpp>
|
||||||
|
#include <boost/program_options/parsers.hpp>
|
||||||
|
|
||||||
|
void wrap_code(std::istream& input, std::ostream& output) {
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(input, line)) {
|
||||||
|
output << line;
|
||||||
|
if (!input.eof())
|
||||||
|
output << std::endl;
|
||||||
|
}
|
||||||
|
output << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wrap_string(std::istream& input, std::ostream& output,
|
||||||
|
const std::string& variable_name)
|
||||||
|
{
|
||||||
|
output << "const std::string " << variable_name << "{" << std::endl;;
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(input, line)) {
|
||||||
|
boost::replace_all(line, "\\", "\\\\");
|
||||||
|
boost::replace_all(line, "\"", "\\\"");
|
||||||
|
output << " \"" << line;
|
||||||
|
if (!input.eof())
|
||||||
|
output << "\\n";
|
||||||
|
output << "\"" << std::endl;
|
||||||
|
}
|
||||||
|
output << "};" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
namespace po = boost::program_options;
|
||||||
|
|
||||||
|
po::options_description desc("Allowed options");
|
||||||
|
desc.add_options()
|
||||||
|
("help", "show help")
|
||||||
|
("output", po::value<std::string>(), "output file")
|
||||||
|
("namespace", po::value<std::string>(), "namespace to use")
|
||||||
|
("input-string,S", po::value<std::vector<std::string>>(),
|
||||||
|
"files to parse as strings")
|
||||||
|
("input-code,C", po::value<std::vector<std::string>>(),
|
||||||
|
"files to parse as code");
|
||||||
|
po::variables_map vm;
|
||||||
|
po::store(po::parse_command_line(argc, argv, desc), vm);
|
||||||
|
po::notify(vm);
|
||||||
|
|
||||||
|
if (vm.count("help")) {
|
||||||
|
std::cout << desc << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vm.count("output")) {
|
||||||
|
std::cout << "Output file not set" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ofstream output(vm["output"].as<std::string>(), std::ios::out);
|
||||||
|
|
||||||
|
if (vm.count("namespace"))
|
||||||
|
output << "namespace " << vm["namespace"].as<std::string>() << " {" << std::endl;
|
||||||
|
|
||||||
|
if (vm.count("input-string")) {
|
||||||
|
for (auto& string_filename: vm["input-string"].as<std::vector<std::string>>()) {
|
||||||
|
std::ifstream input(string_filename, std::ios::in);
|
||||||
|
wrap_string(input, output,
|
||||||
|
boost::replace_all_copy(string_filename, ".", "_"));
|
||||||
|
input.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vm.count("input-code")) {
|
||||||
|
for (auto& data_filename: vm["input-code"].as<std::vector<std::string>>()) {
|
||||||
|
std::ifstream input(data_filename, std::ios::in);
|
||||||
|
wrap_code(input, output);
|
||||||
|
input.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vm.count("namespace"))
|
||||||
|
output << "}" << std::endl;
|
||||||
|
|
||||||
|
output.close();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -7,11 +7,11 @@
|
|||||||
using namespace mstchtest;
|
using namespace mstchtest;
|
||||||
|
|
||||||
#define MSTCH_PARTIAL_TEST(x) TEST_CASE(#x) { \
|
#define MSTCH_PARTIAL_TEST(x) TEST_CASE(#x) { \
|
||||||
REQUIRE(x ## _txt == mstch::render(x ## _mustache, x ## _data, {{"partial", x ## _partial}})); \
|
REQUIRE(x ## _txt == mstch::render(x ## _mustache, x ## _data, {{"partial", x ## _partial}})); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MSTCH_TEST(x) TEST_CASE(#x) { \
|
#define MSTCH_TEST(x) TEST_CASE(#x) { \
|
||||||
REQUIRE(x ## _txt == mstch::render(x ## _mustache, x ## _data)); \
|
REQUIRE(x ## _txt == mstch::render(x ## _mustache, x ## _data)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
MSTCH_TEST(ampersand_escape)
|
MSTCH_TEST(ampersand_escape)
|
||||||
|
Loading…
Reference in New Issue
Block a user