You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

269 lines
7.0 KiB

  1. /*
  2. cpptempl
  3. =================
  4. This is a template engine for C++.
  5. Syntax
  6. =================
  7. Variables: {$variable_name}
  8. Loops: {% for person in people %}Name: {$person.name}{% endfor %}
  9. If: {% for person.name == "Bob" %}Full name: Robert{% endif %}
  10. Copyright
  11. ==================
  12. Author: Ryan Ginstrom
  13. MIT License
  14. Usage
  15. =======================
  16. std::string text = "{% if item %}{$item}{% endif %}\n"
  17. "{% if thing %}{$thing}{% endif %}" ;
  18. cpptempl::data_map data ;
  19. data["item"] = cpptempl::make_data("aaa") ;
  20. data["thing"] = cpptempl::make_data("bbb") ;
  21. std::string result = cpptempl::parse(text, data) ;
  22. Handy Functions
  23. ========================
  24. make_data() : Feed it a string, data_map, or data_list to create a data entry.
  25. Example:
  26. data_map person ;
  27. person["name"] = make_data("Bob") ;
  28. person["occupation"] = make_data("Plumber") ;
  29. data_map data ;
  30. data["person"] = make_data(person) ;
  31. std::string result = parse(templ_text, data) ;
  32. */
  33. #pragma once
  34. #ifdef _WIN32
  35. #pragma warning( disable : 4996 ) // 'std::copy': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'
  36. #pragma warning( disable : 4512 ) // 'std::copy': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'
  37. #endif
  38. #include <string>
  39. #include <vector>
  40. #include <map>
  41. #include <memory>
  42. #include <unordered_map>
  43. #include <boost/lexical_cast.hpp>
  44. #include <iostream>
  45. namespace cpptempl
  46. {
  47. // various typedefs
  48. // data classes
  49. class Data ;
  50. class DataValue ;
  51. class DataList ;
  52. class DataMap ;
  53. class data_ptr {
  54. public:
  55. data_ptr() {}
  56. template<typename T> data_ptr(const T& data) {
  57. this->operator =(data);
  58. }
  59. data_ptr(DataValue* data);
  60. data_ptr(DataList* data);
  61. data_ptr(DataMap* data);
  62. data_ptr(const data_ptr& data) {
  63. ptr = data.ptr;
  64. }
  65. template<typename T> void operator = (const T& data);
  66. void push_back(const data_ptr& data);
  67. virtual ~data_ptr() {}
  68. Data* operator ->() {
  69. return ptr.get();
  70. }
  71. private:
  72. std::shared_ptr<Data> ptr;
  73. };
  74. typedef std::vector<data_ptr> data_list ;
  75. class data_map {
  76. public:
  77. data_ptr& operator [](const std::string& key);
  78. bool empty();
  79. bool has(const std::string& key);
  80. private:
  81. std::unordered_map<std::string, data_ptr> data;
  82. };
  83. template<> inline void data_ptr::operator = (const data_ptr& data);
  84. template<> void data_ptr::operator = (const std::string& data);
  85. template<> void data_ptr::operator = (const std::string& data);
  86. template<> void data_ptr::operator = (const data_map& data);
  87. template<typename T>
  88. void data_ptr::operator = (const T& data) {
  89. std::string data_str = boost::lexical_cast<std::string>(data);
  90. this->operator =(data_str);
  91. }
  92. // token classes
  93. class Token ;
  94. typedef std::shared_ptr<Token> token_ptr ;
  95. typedef std::vector<token_ptr> token_vector ;
  96. // Custom exception class for library errors
  97. class TemplateException : public std::exception
  98. {
  99. public:
  100. TemplateException(std::string reason) : m_reason(reason){}
  101. ~TemplateException() {}
  102. const char* what() const noexcept {
  103. return m_reason.c_str();
  104. }
  105. private:
  106. std::string m_reason;
  107. };
  108. // Data types used in templates
  109. class Data
  110. {
  111. public:
  112. virtual bool empty() = 0 ;
  113. virtual std::string getvalue();
  114. virtual data_list& getlist();
  115. virtual data_map& getmap() ;
  116. };
  117. class DataValue : public Data
  118. {
  119. std::string m_value ;
  120. public:
  121. DataValue(std::string value) : m_value(value){}
  122. std::string getvalue();
  123. bool empty();
  124. };
  125. class DataList : public Data
  126. {
  127. data_list m_items ;
  128. public:
  129. DataList(const data_list &items) : m_items(items){}
  130. data_list& getlist() ;
  131. bool empty();
  132. };
  133. class DataMap : public Data
  134. {
  135. data_map m_items ;
  136. public:
  137. DataMap(const data_map &items) : m_items(items){}
  138. data_map& getmap();
  139. bool empty();
  140. };
  141. // convenience functions for making data objects
  142. inline data_ptr make_data(std::string val)
  143. {
  144. return data_ptr(new DataValue(val)) ;
  145. }
  146. inline data_ptr make_data(data_list &val)
  147. {
  148. return data_ptr(new DataList(val)) ;
  149. }
  150. inline data_ptr make_data(data_map &val)
  151. {
  152. return data_ptr(new DataMap(val)) ;
  153. }
  154. // get a data value from a data map
  155. // e.g. foo.bar => data["foo"]["bar"]
  156. data_ptr parse_val(std::string key, data_map &data) ;
  157. typedef enum
  158. {
  159. TOKEN_TYPE_NONE,
  160. TOKEN_TYPE_TEXT,
  161. TOKEN_TYPE_VAR,
  162. TOKEN_TYPE_IF,
  163. TOKEN_TYPE_FOR,
  164. TOKEN_TYPE_ENDIF,
  165. TOKEN_TYPE_ENDFOR,
  166. } TokenType;
  167. // Template tokens
  168. // base class for all token types
  169. class Token
  170. {
  171. public:
  172. virtual TokenType gettype() = 0 ;
  173. virtual void gettext(std::ostream &stream, data_map &data) = 0 ;
  174. virtual void set_children(token_vector &children);
  175. virtual token_vector & get_children();
  176. };
  177. // normal text
  178. class TokenText : public Token
  179. {
  180. std::string m_text ;
  181. public:
  182. TokenText(std::string text) : m_text(text){}
  183. TokenType gettype();
  184. void gettext(std::ostream &stream, data_map &data);
  185. };
  186. // variable
  187. class TokenVar : public Token
  188. {
  189. std::string m_key ;
  190. public:
  191. TokenVar(std::string key) : m_key(key){}
  192. TokenType gettype();
  193. void gettext(std::ostream &stream, data_map &data);
  194. };
  195. // for block
  196. class TokenFor : public Token
  197. {
  198. public:
  199. std::string m_key ;
  200. std::string m_val ;
  201. token_vector m_children ;
  202. TokenFor(std::string expr);
  203. TokenType gettype();
  204. void gettext(std::ostream &stream, data_map &data);
  205. void set_children(token_vector &children);
  206. token_vector &get_children();
  207. };
  208. // if block
  209. class TokenIf : public Token
  210. {
  211. public:
  212. std::string m_expr ;
  213. token_vector m_children ;
  214. TokenIf(std::string expr) : m_expr(expr){}
  215. TokenType gettype();
  216. void gettext(std::ostream &stream, data_map &data);
  217. bool is_true(std::string expr, data_map &data);
  218. void set_children(token_vector &children);
  219. token_vector &get_children();
  220. };
  221. // end of block
  222. class TokenEnd : public Token // end of control block
  223. {
  224. std::string m_type ;
  225. public:
  226. TokenEnd(std::string text) : m_type(text){}
  227. TokenType gettype();
  228. void gettext(std::ostream &stream, data_map &data);
  229. };
  230. std::string gettext(token_ptr token, data_map &data) ;
  231. void parse_tree(token_vector &tokens, token_vector &tree, TokenType until=TOKEN_TYPE_NONE) ;
  232. token_vector & tokenize(std::string text, token_vector &tokens) ;
  233. // The big daddy. Pass in the template and data,
  234. // and get out a completed doc.
  235. void parse(std::ostream &stream, std::string templ_text, data_map &data) ;
  236. std::string parse(std::string templ_text, data_map &data);
  237. std::string parse(std::string templ_text, data_map &data);
  238. }