David Reiss | ea2cba8 | 2009-03-30 21:35:00 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Licensed to the Apache Software Foundation (ASF) under one |
| 3 | * or more contributor license agreements. See the NOTICE file |
| 4 | * distributed with this work for additional information |
| 5 | * regarding copyright ownership. The ASF licenses this file |
| 6 | * to you under the Apache License, Version 2.0 (the |
| 7 | * "License"); you may not use this file except in compliance |
| 8 | * with the License. You may obtain a copy of the License at |
| 9 | * |
| 10 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | * |
| 12 | * Unless required by applicable law or agreed to in writing, |
| 13 | * software distributed under the License is distributed on an |
| 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 15 | * KIND, either express or implied. See the License for the |
| 16 | * specific language governing permissions and limitations |
| 17 | * under the License. |
| 18 | */ |
Mark Slee | e9ce01c | 2007-05-16 02:29:53 +0000 | [diff] [blame] | 19 | |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 20 | #ifndef T_GENERATOR_H |
| 21 | #define T_GENERATOR_H |
| 22 | |
| 23 | #include <string> |
| 24 | #include <iostream> |
David Reiss | 39aa00d | 2009-03-26 08:40:18 +0000 | [diff] [blame] | 25 | #include <fstream> |
Mark Slee | e854063 | 2006-05-30 09:24:40 +0000 | [diff] [blame] | 26 | #include <sstream> |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 27 | #include "parse/t_program.h" |
Mark Slee | 0e0ff7e | 2007-01-18 22:59:59 +0000 | [diff] [blame] | 28 | #include "globals.h" |
Bryan Duxbury | e0ac3ab | 2010-07-29 16:24:41 +0000 | [diff] [blame] | 29 | #include "t_generator_registry.h" |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 30 | |
| 31 | /** |
| 32 | * Base class for a thrift code generator. This class defines the basic |
| 33 | * routines for code generation and contains the top level method that |
| 34 | * dispatches code generation across various components. |
| 35 | * |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 36 | */ |
| 37 | class t_generator { |
| 38 | public: |
Mark Slee | f0712dc | 2006-10-25 19:03:57 +0000 | [diff] [blame] | 39 | t_generator(t_program* program) { |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 40 | tmp_ = 0; |
Mark Slee | f0712dc | 2006-10-25 19:03:57 +0000 | [diff] [blame] | 41 | indent_ = 0; |
| 42 | program_ = program; |
| 43 | program_name_ = get_program_name(program); |
David Reiss | 82e6fc0 | 2009-03-26 23:32:36 +0000 | [diff] [blame] | 44 | escape_['\n'] = "\\n"; |
| 45 | escape_['\r'] = "\\r"; |
| 46 | escape_['\t'] = "\\t"; |
| 47 | escape_['"'] = "\\\""; |
| 48 | escape_['\\'] = "\\\\"; |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 49 | } |
| 50 | |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 51 | virtual ~t_generator() {} |
| 52 | |
| 53 | /** |
| 54 | * Framework generator method that iterates over all the parts of a program |
| 55 | * and performs general actions. This is implemented by the base class and |
David Reiss | b4d7b89 | 2008-03-27 21:40:01 +0000 | [diff] [blame] | 56 | * should not normally be overwritten in the subclasses. |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 57 | */ |
David Reiss | b4d7b89 | 2008-03-27 21:40:01 +0000 | [diff] [blame] | 58 | virtual void generate_program(); |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 59 | |
kholst | 76f2c88 | 2008-01-16 02:47:41 +0000 | [diff] [blame] | 60 | const t_program* get_program() const { return program_; } |
| 61 | |
David Reiss | 39aa00d | 2009-03-26 08:40:18 +0000 | [diff] [blame] | 62 | void generate_docstring_comment(std::ofstream& out, |
| 63 | const std::string& comment_start, |
| 64 | const std::string& line_prefix, |
| 65 | const std::string& contents, |
| 66 | const std::string& comment_end); |
David Reiss | 82e6fc0 | 2009-03-26 23:32:36 +0000 | [diff] [blame] | 67 | |
| 68 | /** |
Bryan Duxbury | 681f5ea | 2010-08-20 16:42:04 +0000 | [diff] [blame] | 69 | * check whether sub-namespace declaraction is used by generator. |
David Reiss | e3ba349 | 2010-08-26 21:49:45 +0000 | [diff] [blame] | 70 | * e.g. allow |
Bryan Duxbury | 681f5ea | 2010-08-20 16:42:04 +0000 | [diff] [blame] | 71 | * namespace py.twisted bar |
| 72 | * to specify namespace to use when -gen py:twisted is specified. |
| 73 | * Will be called with subnamespace, i.e. is_valid_namespace("twisted") |
| 74 | * will be called for the above example. |
| 75 | */ |
Roger Meier | 3b771a1 | 2010-11-17 22:11:26 +0000 | [diff] [blame] | 76 | static bool is_valid_namespace(const std::string& sub_namespace) { |
| 77 | (void) sub_namespace; |
| 78 | return false; |
| 79 | } |
Bryan Duxbury | 681f5ea | 2010-08-20 16:42:04 +0000 | [diff] [blame] | 80 | |
| 81 | /** |
David Reiss | 82e6fc0 | 2009-03-26 23:32:36 +0000 | [diff] [blame] | 82 | * Escape string to use one in generated sources. |
| 83 | */ |
| 84 | virtual std::string escape_string(const std::string &in) const; |
| 85 | |
| 86 | std::string get_escaped_string(t_const_value* constval) { |
| 87 | return escape_string(constval->get_string()); |
| 88 | } |
| 89 | |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 90 | protected: |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 91 | |
| 92 | /** |
| 93 | * Optional methods that may be imlemented by subclasses to take necessary |
| 94 | * steps at the beginning or end of code generation. |
| 95 | */ |
Mark Slee | e854063 | 2006-05-30 09:24:40 +0000 | [diff] [blame] | 96 | |
Mark Slee | f0712dc | 2006-10-25 19:03:57 +0000 | [diff] [blame] | 97 | virtual void init_generator() {} |
| 98 | virtual void close_generator() {} |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 99 | |
Mark Slee | aa7671d | 2006-11-29 03:19:31 +0000 | [diff] [blame] | 100 | virtual void generate_consts(std::vector<t_const*> consts); |
| 101 | |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 102 | /** |
| 103 | * Pure virtual methods implemented by the generator subclasses. |
| 104 | */ |
Mark Slee | e854063 | 2006-05-30 09:24:40 +0000 | [diff] [blame] | 105 | |
Mark Slee | 9cb7c61 | 2006-09-01 22:17:45 +0000 | [diff] [blame] | 106 | virtual void generate_typedef (t_typedef* ttypedef) = 0; |
| 107 | virtual void generate_enum (t_enum* tenum) = 0; |
Roger Meier | 3b771a1 | 2010-11-17 22:11:26 +0000 | [diff] [blame] | 108 | virtual void generate_const (t_const* tconst) { |
| 109 | (void) tconst; |
| 110 | } |
Mark Slee | 9cb7c61 | 2006-09-01 22:17:45 +0000 | [diff] [blame] | 111 | virtual void generate_struct (t_struct* tstruct) = 0; |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 112 | virtual void generate_service (t_service* tservice) = 0; |
Mark Slee | 9cb7c61 | 2006-09-01 22:17:45 +0000 | [diff] [blame] | 113 | virtual void generate_xception (t_struct* txception) { |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 114 | // By default exceptions are the same as structs |
Mark Slee | 9cb7c61 | 2006-09-01 22:17:45 +0000 | [diff] [blame] | 115 | generate_struct(txception); |
| 116 | } |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 117 | |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 118 | /** |
| 119 | * Method to get the program name, may be overridden |
| 120 | */ |
Mark Slee | e854063 | 2006-05-30 09:24:40 +0000 | [diff] [blame] | 121 | virtual std::string get_program_name(t_program* tprogram) { |
| 122 | return tprogram->get_name(); |
| 123 | } |
| 124 | |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 125 | /** |
| 126 | * Method to get the service name, may be overridden |
| 127 | */ |
Mark Slee | e854063 | 2006-05-30 09:24:40 +0000 | [diff] [blame] | 128 | virtual std::string get_service_name(t_service* tservice) { |
| 129 | return tservice->get_name(); |
| 130 | } |
| 131 | |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 132 | /** |
dweatherford | 65b7075 | 2007-10-31 02:18:14 +0000 | [diff] [blame] | 133 | * Get the current output directory |
| 134 | */ |
| 135 | virtual std::string get_out_dir() const { |
| 136 | return program_->get_out_path() + out_dir_base_ + "/"; |
| 137 | } |
| 138 | |
| 139 | /** |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 140 | * Creates a unique temporary variable name, which is just "name" with a |
| 141 | * number appended to it (i.e. name35) |
| 142 | */ |
Mark Slee | e854063 | 2006-05-30 09:24:40 +0000 | [diff] [blame] | 143 | std::string tmp(std::string name) { |
| 144 | std::ostringstream out; |
| 145 | out << name << tmp_++; |
| 146 | return out.str(); |
| 147 | } |
| 148 | |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 149 | /** |
| 150 | * Indentation level modifiers |
| 151 | */ |
Mark Slee | e854063 | 2006-05-30 09:24:40 +0000 | [diff] [blame] | 152 | |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 153 | void indent_up(){ |
| 154 | ++indent_; |
| 155 | } |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 156 | |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 157 | void indent_down() { |
| 158 | --indent_; |
| 159 | } |
| 160 | |
| 161 | /** |
| 162 | * Indentation print function |
| 163 | */ |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 164 | std::string indent() { |
| 165 | std::string ind = ""; |
| 166 | int i; |
| 167 | for (i = 0; i < indent_; ++i) { |
| 168 | ind += " "; |
| 169 | } |
| 170 | return ind; |
| 171 | } |
| 172 | |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 173 | /** |
| 174 | * Indentation utility wrapper |
| 175 | */ |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 176 | std::ostream& indent(std::ostream &os) { |
| 177 | return os << indent(); |
| 178 | } |
David Reiss | 3429b6a | 2007-08-15 00:55:41 +0000 | [diff] [blame] | 179 | |
iproctor | 9a41a0c | 2007-07-16 21:59:24 +0000 | [diff] [blame] | 180 | /** |
| 181 | * Capitalization helpers |
| 182 | */ |
| 183 | std::string capitalize(std::string in) { |
| 184 | in[0] = toupper(in[0]); |
| 185 | return in; |
| 186 | } |
| 187 | std::string decapitalize(std::string in) { |
| 188 | in[0] = tolower(in[0]); |
| 189 | return in; |
| 190 | } |
Mark Slee | e02ab33 | 2007-11-28 04:17:49 +0000 | [diff] [blame] | 191 | std::string lowercase(std::string in) { |
| 192 | for (size_t i = 0; i < in.size(); ++i) { |
| 193 | in[i] = tolower(in[i]); |
| 194 | } |
| 195 | return in; |
| 196 | } |
Todd Lipcon | b6f4e56 | 2010-01-19 05:18:55 +0000 | [diff] [blame] | 197 | /** |
| 198 | * Transforms a camel case string to an equivalent one separated by underscores |
| 199 | * e.g. aMultiWord -> a_multi_word |
| 200 | * someName -> some_name |
| 201 | * CamelCase -> camel_case |
| 202 | * name -> name |
| 203 | * Name -> name |
| 204 | */ |
Kevin Clark | 19f8d1f | 2009-04-07 19:09:28 +0000 | [diff] [blame] | 205 | std::string underscore(std::string in) { |
| 206 | in[0] = tolower(in[0]); |
| 207 | for (size_t i = 1; i < in.size(); ++i) { |
| 208 | if (isupper(in[i])) { |
| 209 | in[i] = tolower(in[i]); |
| 210 | in.insert(i, "_"); |
| 211 | } |
| 212 | } |
| 213 | return in; |
| 214 | } |
Todd Lipcon | b6f4e56 | 2010-01-19 05:18:55 +0000 | [diff] [blame] | 215 | /** |
| 216 | * Transforms a string with words separated by underscores to a camel case equivalent |
| 217 | * e.g. a_multi_word -> aMultiWord |
| 218 | * some_name -> someName |
| 219 | * name -> name |
| 220 | */ |
| 221 | std::string camelcase(std::string in) { |
| 222 | std::ostringstream out; |
| 223 | bool underscore = false; |
| 224 | |
| 225 | for (size_t i = 0; i < in.size(); i++) { |
| 226 | if (in[i] == '_') { |
| 227 | underscore = true; |
| 228 | continue; |
| 229 | } |
| 230 | if (underscore) { |
| 231 | out << (char) toupper(in[i]); |
| 232 | underscore = false; |
| 233 | continue; |
| 234 | } |
| 235 | out << in[i]; |
| 236 | } |
| 237 | |
| 238 | return out.str(); |
| 239 | } |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 240 | |
David Reiss | 3429b6a | 2007-08-15 00:55:41 +0000 | [diff] [blame] | 241 | /** |
| 242 | * Get the true type behind a series of typedefs. |
| 243 | */ |
| 244 | static t_type* get_true_type(t_type* type) { |
David Reiss | 41d3058 | 2010-10-05 16:39:29 +0000 | [diff] [blame] | 245 | return type->get_true_type(); |
David Reiss | 3429b6a | 2007-08-15 00:55:41 +0000 | [diff] [blame] | 246 | } |
| 247 | |
Mark Slee | e854063 | 2006-05-30 09:24:40 +0000 | [diff] [blame] | 248 | protected: |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 249 | /** |
Mark Slee | f0712dc | 2006-10-25 19:03:57 +0000 | [diff] [blame] | 250 | * The program being generated |
| 251 | */ |
| 252 | t_program* program_; |
| 253 | |
| 254 | /** |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 255 | * Quick accessor for formatted program name that is currently being |
| 256 | * generated. |
| 257 | */ |
Mark Slee | e854063 | 2006-05-30 09:24:40 +0000 | [diff] [blame] | 258 | std::string program_name_; |
| 259 | |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 260 | /** |
| 261 | * Quick accessor for formatted service name that is currently being |
| 262 | * generated. |
| 263 | */ |
Mark Slee | e854063 | 2006-05-30 09:24:40 +0000 | [diff] [blame] | 264 | std::string service_name_; |
| 265 | |
dweatherford | 65b7075 | 2007-10-31 02:18:14 +0000 | [diff] [blame] | 266 | /** |
| 267 | * Output type-specifc directory name ("gen-*") |
| 268 | */ |
| 269 | std::string out_dir_base_; |
| 270 | |
David Reiss | 82e6fc0 | 2009-03-26 23:32:36 +0000 | [diff] [blame] | 271 | /** |
| 272 | * Map of characters to escape in string literals. |
| 273 | */ |
| 274 | std::map<char, std::string> escape_; |
| 275 | |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 276 | private: |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 277 | /** |
| 278 | * Current code indentation level |
| 279 | */ |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 280 | int indent_; |
| 281 | |
Mark Slee | f5377b3 | 2006-10-10 01:42:59 +0000 | [diff] [blame] | 282 | /** |
| 283 | * Temporary variable counter, for making unique variable names |
| 284 | */ |
Mark Slee | e854063 | 2006-05-30 09:24:40 +0000 | [diff] [blame] | 285 | int tmp_; |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 286 | }; |
| 287 | |
Mark Slee | 3198572 | 2006-05-24 21:45:31 +0000 | [diff] [blame] | 288 | #endif |