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
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							271 lines
						
					
					
						
							7.1 KiB
						
					
					
				| /* | |
| cpptempl | |
| ================= | |
| This is a template engine for C++. | |
|  | |
| Syntax | |
| ================= | |
| Variables: {$variable_name} | |
| Loops: {% for person in people %}Name: {$person.name}{% endfor %} | |
| If: {% for person.name == "Bob" %}Full name: Robert{% endif %} | |
|  | |
| Copyright | |
| ================== | |
| Author: Ryan Ginstrom | |
| MIT License | |
|  | |
| Usage | |
| ======================= | |
|     std::string text = "{% if item %}{$item}{% endif %}\n" | |
| 		"{% if thing %}{$thing}{% endif %}" ; | |
| 	cpptempl::data_map data ; | |
| 	data["item"] = cpptempl::make_data("aaa") ; | |
| 	data["thing"] = cpptempl::make_data("bbb") ; | |
|  | |
|     std::string result = cpptempl::parse(text, data) ; | |
|  | |
| Handy Functions | |
| ======================== | |
| make_data() : Feed it a string, data_map, or data_list to create a data entry. | |
| Example: | |
| 	data_map person ; | |
| 	person["name"] = make_data("Bob") ; | |
| 	person["occupation"] = make_data("Plumber") ; | |
| 	data_map data ; | |
| 	data["person"] = make_data(person) ; | |
|     std::string result = parse(templ_text, data) ; | |
|  | |
| */ | |
| #pragma once | |
|  | |
| #ifdef _WIN32 | |
| #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' | |
| #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' | |
| #endif | |
|  | |
| #include <string> | |
| #include <vector> | |
| #include <map>							 | |
| #include <memory> | |
| #include <unordered_map> | |
| #include <boost/lexical_cast.hpp> | |
|  | |
| #include <iostream> | |
|  | |
| namespace cpptempl | |
| { | |
| 	// various typedefs | |
|  | |
| 	// data classes | |
| 	class Data ; | |
| 	class DataValue ; | |
| 	class DataList ; | |
| 	class DataMap ; | |
| 
 | |
| 	class data_ptr { | |
| 	public: | |
| 		data_ptr() {} | |
| 		template<typename T> data_ptr(const T& data) { | |
| 			this->operator =(data); | |
| 		} | |
|         data_ptr(DataValue* data); | |
|         data_ptr(DataList* data); | |
|         data_ptr(DataMap* data); | |
| 		data_ptr(const data_ptr& data) { | |
| 			ptr = data.ptr; | |
| 		} | |
| 		template<typename T> void operator = (const T& data); | |
| 		void push_back(const data_ptr& data); | |
| 		virtual ~data_ptr() {} | |
| 		Data* operator ->() { | |
| 			return ptr.get(); | |
| 		} | |
| 	private: | |
| 		std::shared_ptr<Data> ptr; | |
| 	}; | |
| 	typedef std::vector<data_ptr> data_list ; | |
| 
 | |
| 	class data_map { | |
| 	public: | |
| 		data_ptr& operator [](const std::string& key); | |
| 		bool empty(); | |
| 		bool has(const std::string& key); | |
| 	private: | |
| 		std::unordered_map<std::string, data_ptr> data; | |
| 	}; | |
| 
 | |
| 	template<> inline void data_ptr::operator = (const data_ptr& data); | |
| 	template<> void data_ptr::operator = (const std::string& data); | |
| 	template<> void data_ptr::operator = (const std::string& data); | |
| 	template<> void data_ptr::operator = (const data_map& data); | |
| 	template<typename T> | |
| 	void data_ptr::operator = (const T& data) { | |
| 		std::string data_str = boost::lexical_cast<std::string>(data); | |
| 		this->operator =(data_str); | |
| 	} | |
| 
 | |
| 	// token classes | |
| 	class Token ; | |
| 	typedef std::shared_ptr<Token> token_ptr ; | |
| 	typedef std::vector<token_ptr> token_vector ; | |
| 
 | |
| 	// Custom exception class for library errors | |
| 	class TemplateException : public std::exception | |
| 	{ | |
| 	public: | |
| 		TemplateException(std::string reason) : m_reason(reason){} | |
| 		~TemplateException() {} | |
| 		const char* what() const noexcept { | |
| 			return m_reason.c_str(); | |
| 		} | |
| 	private: | |
| 		std::string m_reason; | |
| 	}; | |
| 
 | |
| 	// Data types used in templates | |
| 	class Data | |
| 	{ | |
| 	public: | |
| 		virtual ~Data() {} | |
| 		virtual bool empty() = 0 ; | |
| 		virtual std::string getvalue(); | |
| 		virtual data_list& getlist(); | |
| 		virtual data_map& getmap() ; | |
| 	}; | |
| 
 | |
| 	class DataValue : public Data | |
| 	{ | |
|         std::string m_value ; | |
| 	public: | |
| 		DataValue(std::string value) : m_value(value){} | |
|         std::string getvalue(); | |
| 		bool empty(); | |
| 	}; | |
| 
 | |
| 	class DataList : public Data | |
| 	{ | |
| 		data_list m_items ; | |
| 	public: | |
| 		DataList(const data_list &items) : m_items(items){} | |
| 		data_list& getlist() ; | |
| 		bool empty(); | |
| 	}; | |
| 
 | |
| 	class DataMap : public Data | |
| 	{ | |
| 		data_map m_items ; | |
| 	public: | |
| 		DataMap(const data_map &items) : m_items(items){} | |
| 		data_map& getmap(); | |
| 		bool empty(); | |
| 	}; | |
| 
 | |
| 	// convenience functions for making data objects | |
| 	inline data_ptr make_data(std::string val) | |
| 	{ | |
| 		return data_ptr(new DataValue(val)) ; | |
| 	} | |
| 	inline data_ptr make_data(data_list &val) | |
| 	{ | |
| 		return data_ptr(new DataList(val)) ; | |
| 	} | |
| 	inline data_ptr make_data(data_map &val) | |
| 	{ | |
| 		return data_ptr(new DataMap(val)) ; | |
| 	} | |
| 	// get a data value from a data map | |
| 	// e.g. foo.bar => data["foo"]["bar"] | |
| 	data_ptr parse_val(std::string key, data_map &data) ; | |
| 
 | |
| 	typedef enum  | |
| 	{ | |
| 		TOKEN_TYPE_NONE, | |
| 		TOKEN_TYPE_TEXT, | |
| 		TOKEN_TYPE_VAR, | |
| 		TOKEN_TYPE_IF, | |
| 		TOKEN_TYPE_FOR, | |
| 		TOKEN_TYPE_ENDIF, | |
| 		TOKEN_TYPE_ENDFOR, | |
| 	} TokenType; | |
| 
 | |
| 	// Template tokens | |
| 	// base class for all token types | |
| 	class Token | |
| 	{ | |
| 	public: | |
| 		virtual ~Token() {}; | |
| 		virtual TokenType gettype() = 0 ; | |
| 		virtual void gettext(std::ostream &stream, data_map &data) = 0 ; | |
| 		virtual void set_children(token_vector &children); | |
| 		virtual token_vector & get_children(); | |
| 	}; | |
| 
 | |
| 	// normal text | |
| 	class TokenText : public Token | |
| 	{ | |
|         std::string m_text ; | |
| 	public: | |
| 		TokenText(std::string text) : m_text(text){} | |
| 		TokenType gettype(); | |
| 		void gettext(std::ostream &stream, data_map &data); | |
| 	}; | |
| 
 | |
| 	// variable | |
| 	class TokenVar : public Token | |
| 	{ | |
|         std::string m_key ; | |
| 	public: | |
| 		TokenVar(std::string key) : m_key(key){} | |
| 		TokenType gettype(); | |
| 		void gettext(std::ostream &stream, data_map &data); | |
| 	}; | |
| 
 | |
| 	// for block | |
| 	class TokenFor : public Token  | |
| 	{ | |
| 	public: | |
|         std::string m_key ; | |
|         std::string m_val ; | |
| 		token_vector m_children ; | |
| 		TokenFor(std::string expr); | |
| 		TokenType gettype(); | |
| 		void gettext(std::ostream &stream, data_map &data); | |
| 		void set_children(token_vector &children); | |
| 		token_vector &get_children(); | |
| 	}; | |
| 
 | |
| 	// if block | |
| 	class TokenIf : public Token | |
| 	{ | |
| 	public: | |
|         std::string m_expr ; | |
| 		token_vector m_children ; | |
| 		TokenIf(std::string expr) : m_expr(expr){} | |
| 		TokenType gettype(); | |
| 		void gettext(std::ostream &stream, data_map &data); | |
| 		bool is_true(std::string expr, data_map &data); | |
| 		void set_children(token_vector &children); | |
| 		token_vector &get_children(); | |
| 	}; | |
| 
 | |
| 	// end of block | |
| 	class TokenEnd : public Token // end of control block | |
| 	{ | |
|         std::string m_type ; | |
| 	public: | |
| 		TokenEnd(std::string text) : m_type(text){} | |
| 		TokenType gettype(); | |
| 		void gettext(std::ostream &stream, data_map &data); | |
| 	}; | |
| 
 | |
|     std::string gettext(token_ptr token, data_map &data) ; | |
| 
 | |
| 	void parse_tree(token_vector &tokens, token_vector &tree, TokenType until=TOKEN_TYPE_NONE) ; | |
| 	token_vector & tokenize(std::string text, token_vector &tokens) ; | |
| 
 | |
| 	// The big daddy. Pass in the template and data,  | |
| 	// and get out a completed doc. | |
| 	void parse(std::ostream &stream, std::string templ_text, data_map &data) ; | |
|     std::string parse(std::string templ_text, data_map &data); | |
| 	std::string parse(std::string templ_text, data_map &data); | |
| }
 |