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.

271 lines
7.1 KiB

2 months ago
  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 ~Data() {}
  113. virtual bool empty() = 0 ;
  114. virtual std::string getvalue();
  115. virtual data_list& getlist();
  116. virtual data_map& getmap() ;
  117. };
  118. class DataValue : public Data
  119. {
  120. std::string m_value ;
  121. public:
  122. DataValue(std::string value) : m_value(value){}
  123. std::string getvalue();
  124. bool empty();
  125. };
  126. class DataList : public Data
  127. {
  128. data_list m_items ;
  129. public:
  130. DataList(const data_list &items) : m_items(items){}
  131. data_list& getlist() ;
  132. bool empty();
  133. };
  134. class DataMap : public Data
  135. {
  136. data_map m_items ;
  137. public:
  138. DataMap(const data_map &items) : m_items(items){}
  139. data_map& getmap();
  140. bool empty();
  141. };
  142. // convenience functions for making data objects
  143. inline data_ptr make_data(std::string val)
  144. {
  145. return data_ptr(new DataValue(val)) ;
  146. }
  147. inline data_ptr make_data(data_list &val)
  148. {
  149. return data_ptr(new DataList(val)) ;
  150. }
  151. inline data_ptr make_data(data_map &val)
  152. {
  153. return data_ptr(new DataMap(val)) ;
  154. }
  155. // get a data value from a data map
  156. // e.g. foo.bar => data["foo"]["bar"]
  157. data_ptr parse_val(std::string key, data_map &data) ;
  158. typedef enum
  159. {
  160. TOKEN_TYPE_NONE,
  161. TOKEN_TYPE_TEXT,
  162. TOKEN_TYPE_VAR,
  163. TOKEN_TYPE_IF,
  164. TOKEN_TYPE_FOR,
  165. TOKEN_TYPE_ENDIF,
  166. TOKEN_TYPE_ENDFOR,
  167. } TokenType;
  168. // Template tokens
  169. // base class for all token types
  170. class Token
  171. {
  172. public:
  173. virtual ~Token() {};
  174. virtual TokenType gettype() = 0 ;
  175. virtual void gettext(std::ostream &stream, data_map &data) = 0 ;
  176. virtual void set_children(token_vector &children);
  177. virtual token_vector & get_children();
  178. };
  179. // normal text
  180. class TokenText : public Token
  181. {
  182. std::string m_text ;
  183. public:
  184. TokenText(std::string text) : m_text(text){}
  185. TokenType gettype();
  186. void gettext(std::ostream &stream, data_map &data);
  187. };
  188. // variable
  189. class TokenVar : public Token
  190. {
  191. std::string m_key ;
  192. public:
  193. TokenVar(std::string key) : m_key(key){}
  194. TokenType gettype();
  195. void gettext(std::ostream &stream, data_map &data);
  196. };
  197. // for block
  198. class TokenFor : public Token
  199. {
  200. public:
  201. std::string m_key ;
  202. std::string m_val ;
  203. token_vector m_children ;
  204. TokenFor(std::string expr);
  205. TokenType gettype();
  206. void gettext(std::ostream &stream, data_map &data);
  207. void set_children(token_vector &children);
  208. token_vector &get_children();
  209. };
  210. // if block
  211. class TokenIf : public Token
  212. {
  213. public:
  214. std::string m_expr ;
  215. token_vector m_children ;
  216. TokenIf(std::string expr) : m_expr(expr){}
  217. TokenType gettype();
  218. void gettext(std::ostream &stream, data_map &data);
  219. bool is_true(std::string expr, data_map &data);
  220. void set_children(token_vector &children);
  221. token_vector &get_children();
  222. };
  223. // end of block
  224. class TokenEnd : public Token // end of control block
  225. {
  226. std::string m_type ;
  227. public:
  228. TokenEnd(std::string text) : m_type(text){}
  229. TokenType gettype();
  230. void gettext(std::ostream &stream, data_map &data);
  231. };
  232. std::string gettext(token_ptr token, data_map &data) ;
  233. void parse_tree(token_vector &tokens, token_vector &tree, TokenType until=TOKEN_TYPE_NONE) ;
  234. token_vector & tokenize(std::string text, token_vector &tokens) ;
  235. // The big daddy. Pass in the template and data,
  236. // and get out a completed doc.
  237. void parse(std::ostream &stream, std::string templ_text, data_map &data) ;
  238. std::string parse(std::string templ_text, data_map &data);
  239. std::string parse(std::string templ_text, data_map &data);
  240. }