Mark Slee | e9ce01c | 2007-05-16 02:29:53 +0000 | [diff] [blame] | 1 | // Copyright (c) 2006- Facebook |
| 2 | // Distributed under the Thrift Software License |
| 3 | // |
| 4 | // See accompanying file LICENSE or visit the Thrift site at: |
| 5 | // http://developers.facebook.com/thrift/ |
| 6 | |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 7 | #ifndef T_GENERATOR_H |
| 8 | #define T_GENERATOR_H |
| 9 | |
| 10 | #include <string> |
| 11 | #include <iostream> |
Mark Slee | e854063 | 2006-05-30 09:24:40 +0000 | [diff] [blame] | 12 | #include <sstream> |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 13 | #include "parse/t_program.h" |
Mark Slee | 0e0ff7e | 2007-01-18 22:59:59 +0000 | [diff] [blame] | 14 | #include "globals.h" |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 15 | |
| 16 | /** |
| 17 | * Base class for a thrift code generator. This class defines the basic |
| 18 | * routines for code generation and contains the top level method that |
| 19 | * dispatches code generation across various components. |
| 20 | * |
| 21 | * @author Mark Slee <mcslee@facebook.com> |
| 22 | */ |
| 23 | class t_generator { |
| 24 | public: |
Mark Slee | f0712dc | 2006-10-25 19:03:57 +0000 | [diff] [blame] | 25 | t_generator(t_program* program) { |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 26 | tmp_ = 0; |
Mark Slee | f0712dc | 2006-10-25 19:03:57 +0000 | [diff] [blame] | 27 | indent_ = 0; |
| 28 | program_ = program; |
| 29 | program_name_ = get_program_name(program); |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 30 | } |
| 31 | |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 32 | virtual ~t_generator() {} |
| 33 | |
| 34 | /** |
| 35 | * Framework generator method that iterates over all the parts of a program |
| 36 | * and performs general actions. This is implemented by the base class and |
David Reiss | b4d7b89 | 2008-03-27 21:40:01 +0000 | [diff] [blame] | 37 | * should not normally be overwritten in the subclasses. |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 38 | */ |
David Reiss | b4d7b89 | 2008-03-27 21:40:01 +0000 | [diff] [blame] | 39 | virtual void generate_program(); |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 40 | |
kholst | 76f2c88 | 2008-01-16 02:47:41 +0000 | [diff] [blame] | 41 | const t_program* get_program() const { return program_; } |
| 42 | |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 43 | protected: |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 44 | |
| 45 | /** |
| 46 | * Optional methods that may be imlemented by subclasses to take necessary |
| 47 | * steps at the beginning or end of code generation. |
| 48 | */ |
Mark Slee | e854063 | 2006-05-30 09:24:40 +0000 | [diff] [blame] | 49 | |
Mark Slee | f0712dc | 2006-10-25 19:03:57 +0000 | [diff] [blame] | 50 | virtual void init_generator() {} |
| 51 | virtual void close_generator() {} |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 52 | |
Mark Slee | aa7671d | 2006-11-29 03:19:31 +0000 | [diff] [blame] | 53 | virtual void generate_consts(std::vector<t_const*> consts); |
| 54 | |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 55 | /** |
| 56 | * Pure virtual methods implemented by the generator subclasses. |
| 57 | */ |
Mark Slee | e854063 | 2006-05-30 09:24:40 +0000 | [diff] [blame] | 58 | |
Mark Slee | 9cb7c61 | 2006-09-01 22:17:45 +0000 | [diff] [blame] | 59 | virtual void generate_typedef (t_typedef* ttypedef) = 0; |
| 60 | virtual void generate_enum (t_enum* tenum) = 0; |
Mark Slee | aa7671d | 2006-11-29 03:19:31 +0000 | [diff] [blame] | 61 | virtual void generate_const (t_const* tconst) {} |
Mark Slee | 9cb7c61 | 2006-09-01 22:17:45 +0000 | [diff] [blame] | 62 | virtual void generate_struct (t_struct* tstruct) = 0; |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 63 | virtual void generate_service (t_service* tservice) = 0; |
Mark Slee | 9cb7c61 | 2006-09-01 22:17:45 +0000 | [diff] [blame] | 64 | virtual void generate_xception (t_struct* txception) { |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 65 | // By default exceptions are the same as structs |
Mark Slee | 9cb7c61 | 2006-09-01 22:17:45 +0000 | [diff] [blame] | 66 | generate_struct(txception); |
| 67 | } |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 68 | |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 69 | /** |
| 70 | * Method to get the program name, may be overridden |
| 71 | */ |
Mark Slee | e854063 | 2006-05-30 09:24:40 +0000 | [diff] [blame] | 72 | virtual std::string get_program_name(t_program* tprogram) { |
| 73 | return tprogram->get_name(); |
| 74 | } |
| 75 | |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 76 | /** |
| 77 | * Method to get the service name, may be overridden |
| 78 | */ |
Mark Slee | e854063 | 2006-05-30 09:24:40 +0000 | [diff] [blame] | 79 | virtual std::string get_service_name(t_service* tservice) { |
| 80 | return tservice->get_name(); |
| 81 | } |
| 82 | |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 83 | /** |
dweatherford | 65b7075 | 2007-10-31 02:18:14 +0000 | [diff] [blame] | 84 | * Get the current output directory |
| 85 | */ |
| 86 | virtual std::string get_out_dir() const { |
| 87 | return program_->get_out_path() + out_dir_base_ + "/"; |
| 88 | } |
| 89 | |
| 90 | /** |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 91 | * Creates a unique temporary variable name, which is just "name" with a |
| 92 | * number appended to it (i.e. name35) |
| 93 | */ |
Mark Slee | e854063 | 2006-05-30 09:24:40 +0000 | [diff] [blame] | 94 | std::string tmp(std::string name) { |
| 95 | std::ostringstream out; |
| 96 | out << name << tmp_++; |
| 97 | return out.str(); |
| 98 | } |
| 99 | |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 100 | /** |
| 101 | * Indentation level modifiers |
| 102 | */ |
Mark Slee | e854063 | 2006-05-30 09:24:40 +0000 | [diff] [blame] | 103 | |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 104 | void indent_up(){ |
| 105 | ++indent_; |
| 106 | } |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 107 | |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 108 | void indent_down() { |
| 109 | --indent_; |
| 110 | } |
| 111 | |
| 112 | /** |
| 113 | * Indentation print function |
| 114 | */ |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 115 | std::string indent() { |
| 116 | std::string ind = ""; |
| 117 | int i; |
| 118 | for (i = 0; i < indent_; ++i) { |
| 119 | ind += " "; |
| 120 | } |
| 121 | return ind; |
| 122 | } |
| 123 | |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 124 | /** |
| 125 | * Indentation utility wrapper |
| 126 | */ |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 127 | std::ostream& indent(std::ostream &os) { |
| 128 | return os << indent(); |
| 129 | } |
David Reiss | 3429b6a | 2007-08-15 00:55:41 +0000 | [diff] [blame] | 130 | |
iproctor | 9a41a0c | 2007-07-16 21:59:24 +0000 | [diff] [blame] | 131 | /** |
| 132 | * Capitalization helpers |
| 133 | */ |
| 134 | std::string capitalize(std::string in) { |
| 135 | in[0] = toupper(in[0]); |
| 136 | return in; |
| 137 | } |
| 138 | std::string decapitalize(std::string in) { |
| 139 | in[0] = tolower(in[0]); |
| 140 | return in; |
| 141 | } |
Mark Slee | e02ab33 | 2007-11-28 04:17:49 +0000 | [diff] [blame] | 142 | std::string lowercase(std::string in) { |
| 143 | for (size_t i = 0; i < in.size(); ++i) { |
| 144 | in[i] = tolower(in[i]); |
| 145 | } |
| 146 | return in; |
| 147 | } |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 148 | |
David Reiss | 3429b6a | 2007-08-15 00:55:41 +0000 | [diff] [blame] | 149 | /** |
| 150 | * Get the true type behind a series of typedefs. |
| 151 | */ |
| 152 | static t_type* get_true_type(t_type* type) { |
| 153 | while (type->is_typedef()) { |
| 154 | type = ((t_typedef*)type)->get_type(); |
| 155 | } |
| 156 | return type; |
| 157 | } |
| 158 | |
Mark Slee | e854063 | 2006-05-30 09:24:40 +0000 | [diff] [blame] | 159 | protected: |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 160 | /** |
Mark Slee | f0712dc | 2006-10-25 19:03:57 +0000 | [diff] [blame] | 161 | * The program being generated |
| 162 | */ |
| 163 | t_program* program_; |
| 164 | |
| 165 | /** |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 166 | * Quick accessor for formatted program name that is currently being |
| 167 | * generated. |
| 168 | */ |
Mark Slee | e854063 | 2006-05-30 09:24:40 +0000 | [diff] [blame] | 169 | std::string program_name_; |
| 170 | |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 171 | /** |
| 172 | * Quick accessor for formatted service name that is currently being |
| 173 | * generated. |
| 174 | */ |
Mark Slee | e854063 | 2006-05-30 09:24:40 +0000 | [diff] [blame] | 175 | std::string service_name_; |
| 176 | |
dweatherford | 65b7075 | 2007-10-31 02:18:14 +0000 | [diff] [blame] | 177 | /** |
| 178 | * Output type-specifc directory name ("gen-*") |
| 179 | */ |
| 180 | std::string out_dir_base_; |
| 181 | |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 182 | private: |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 183 | /** |
| 184 | * Current code indentation level |
| 185 | */ |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 186 | int indent_; |
| 187 | |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 188 | /** |
| 189 | * Temporary variable counter, for making unique variable names |
| 190 | */ |
Mark Slee | e854063 | 2006-05-30 09:24:40 +0000 | [diff] [blame] | 191 | int tmp_; |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 192 | }; |
| 193 | |
David Reiss | bd0db88 | 2008-02-27 01:54:51 +0000 | [diff] [blame] | 194 | |
| 195 | /** |
| 196 | * A factory for producing generator classes of a particular language. |
| 197 | * |
| 198 | * This class is also responsible for: |
| 199 | * - Registering itself with the generator registry. |
| 200 | * - Providing documentation for the generators it produces. |
| 201 | */ |
| 202 | class t_generator_factory { |
| 203 | public: |
| 204 | t_generator_factory(const std::string& short_name, |
| 205 | const std::string& long_name, |
| 206 | const std::string& documentation); |
| 207 | |
| 208 | virtual ~t_generator_factory() {} |
| 209 | |
| 210 | virtual t_generator* get_generator( |
| 211 | // The program to generate. |
| 212 | t_program* program, |
| 213 | // Note: parsed_options will not exist beyond the call to get_generator. |
| 214 | const std::map<std::string, std::string>& parsed_options, |
| 215 | // Note: option_string might not exist beyond the call to get_generator. |
| 216 | const std::string& option_string) |
| 217 | = 0; |
| 218 | |
| 219 | std::string get_short_name() { return short_name_; } |
| 220 | std::string get_long_name() { return long_name_; } |
| 221 | std::string get_documentation() { return documentation_; } |
| 222 | |
| 223 | private: |
| 224 | std::string short_name_; |
| 225 | std::string long_name_; |
| 226 | std::string documentation_; |
| 227 | }; |
| 228 | |
| 229 | template <typename generator> |
| 230 | class t_generator_factory_impl : public t_generator_factory { |
| 231 | public: |
| 232 | t_generator_factory_impl(const std::string& short_name, |
| 233 | const std::string& long_name, |
| 234 | const std::string& documentation) |
| 235 | : t_generator_factory(short_name, long_name, documentation) |
| 236 | {} |
| 237 | |
| 238 | virtual t_generator* get_generator( |
| 239 | t_program* program, |
| 240 | const std::map<std::string, std::string>& parsed_options, |
| 241 | const std::string& option_string) { |
| 242 | return new generator(program, parsed_options, option_string); |
| 243 | } |
| 244 | }; |
| 245 | |
| 246 | class t_generator_registry { |
| 247 | public: |
| 248 | static void register_generator(t_generator_factory* factory); |
| 249 | |
| 250 | static t_generator* get_generator(t_program* program, |
| 251 | const std::string& options); |
| 252 | |
| 253 | typedef std::map<std::string, t_generator_factory*> gen_map_t; |
| 254 | static gen_map_t& get_generator_map(); |
| 255 | |
| 256 | private: |
| 257 | t_generator_registry(); |
| 258 | t_generator_registry(const t_generator_registry&); |
| 259 | }; |
| 260 | |
| 261 | #define THRIFT_REGISTER_GENERATOR(language, long_name, doc) \ |
| 262 | class t_##language##_generator_factory_impl \ |
| 263 | : public t_generator_factory_impl<t_##language##_generator> \ |
| 264 | { \ |
| 265 | public: \ |
| 266 | t_##language##_generator_factory_impl() \ |
| 267 | : t_generator_factory_impl<t_##language##_generator>( \ |
| 268 | #language, long_name, doc) \ |
| 269 | {} \ |
| 270 | }; \ |
| 271 | static t_##language##_generator_factory_impl _registerer; |
| 272 | |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 273 | #endif |