blob: cfab691328348c884412b4fe084282c271c0ecbd [file] [log] [blame]
David Reissea2cba82009-03-30 21:35:00 +00001/*
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 Sleee9ce01c2007-05-16 02:29:53 +000019
Mark Slee31985722006-05-24 21:45:31 +000020#ifndef T_PROGRAM_H
21#define T_PROGRAM_H
22
Mark Sleee8540632006-05-30 09:24:40 +000023#include <map>
Mark Slee31985722006-05-24 21:45:31 +000024#include <string>
25#include <vector>
26
Mark Sleef0712dc2006-10-25 19:03:57 +000027// For program_name()
28#include "main.h"
29
David Reissc2532a92007-07-30 23:46:11 +000030#include "t_doc.h"
Mark Sleef0712dc2006-10-25 19:03:57 +000031#include "t_scope.h"
Mark Slee31985722006-05-24 21:45:31 +000032#include "t_base_type.h"
33#include "t_typedef.h"
34#include "t_enum.h"
Mark Slee30152872006-11-28 01:24:07 +000035#include "t_const.h"
Mark Slee31985722006-05-24 21:45:31 +000036#include "t_struct.h"
37#include "t_service.h"
Mark Sleee8540632006-05-30 09:24:40 +000038#include "t_list.h"
39#include "t_map.h"
40#include "t_set.h"
Bryan Duxburye0ac3ab2010-07-29 16:24:41 +000041#include "generate/t_generator_registry.h"
ccheeverf53b5cf2007-02-05 20:33:11 +000042//#include "t_doc.h"
Mark Slee31985722006-05-24 21:45:31 +000043
44/**
45 * Top level class representing an entire thrift program. A program consists
46 * fundamentally of the following:
47 *
48 * Typedefs
49 * Enumerations
Mark Slee30152872006-11-28 01:24:07 +000050 * Constants
Mark Slee31985722006-05-24 21:45:31 +000051 * Structs
Mark Slee9cb7c612006-09-01 22:17:45 +000052 * Exceptions
Mark Slee31985722006-05-24 21:45:31 +000053 * Services
54 *
Mark Sleef5377b32006-10-10 01:42:59 +000055 * The program module also contains the definitions of the base types.
56 *
Mark Slee31985722006-05-24 21:45:31 +000057 */
David Reissc2532a92007-07-30 23:46:11 +000058class t_program : public t_doc {
Konrad Grochowski16a23a62014-11-13 15:33:38 +010059public:
60 t_program(std::string path, std::string name)
61 : path_(path), name_(name), out_path_("./"), out_path_is_absolute_(false) {
Mark Sleef0712dc2006-10-25 19:03:57 +000062 scope_ = new t_scope();
Mark Slee31985722006-05-24 21:45:31 +000063 }
64
Konrad Grochowski16a23a62014-11-13 15:33:38 +010065 t_program(std::string path) : path_(path), out_path_("./"), out_path_is_absolute_(false) {
Mark Sleef0712dc2006-10-25 19:03:57 +000066 name_ = program_name(path);
67 scope_ = new t_scope();
Mark Slee31985722006-05-24 21:45:31 +000068 }
69
Konrad Grochowski16a23a62014-11-13 15:33:38 +010070 ~t_program() {
71 if (scope_) {
72 delete scope_;
73 scope_ = NULL;
74 }
Roger Meier4f4b15b2014-11-05 16:51:04 +010075 }
Jens Geyer09b97c72013-08-04 13:39:09 +020076
Mark Slee2c44d202007-05-16 02:18:07 +000077 // Path accessor
Mark Sleef0712dc2006-10-25 19:03:57 +000078 const std::string& get_path() const { return path_; }
79
dweatherford65b70752007-10-31 02:18:14 +000080 // Output path accessor
81 const std::string& get_out_path() const { return out_path_; }
82
Bryan Duxburybdca9f62011-03-01 19:53:07 +000083 // Create gen-* dir accessor
Roger Meiera70986f2014-10-21 23:01:36 +020084 bool is_out_path_absolute() const { return out_path_is_absolute_; }
Bryan Duxburybdca9f62011-03-01 19:53:07 +000085
Mark Slee31985722006-05-24 21:45:31 +000086 // Name accessor
Mark Sleef0712dc2006-10-25 19:03:57 +000087 const std::string& get_name() const { return name_; }
Mark Slee31985722006-05-24 21:45:31 +000088
Mark Slee9cb7c612006-09-01 22:17:45 +000089 // Namespace
Mark Sleef0712dc2006-10-25 19:03:57 +000090 const std::string& get_namespace() const { return namespace_; }
Mark Slee9cb7c612006-09-01 22:17:45 +000091
kholst76f2c882008-01-16 02:47:41 +000092 // Include prefix accessor
93 const std::string& get_include_prefix() const { return include_prefix_; }
94
Mark Slee31985722006-05-24 21:45:31 +000095 // Accessors for program elements
Konrad Grochowskidae6d3c2014-12-01 11:26:07 +010096 const std::vector<t_typedef*>& get_typedefs() const { return typedefs_; }
97 const std::vector<t_enum*>& get_enums() const { return enums_; }
98 const std::vector<t_const*>& get_consts() const { return consts_; }
99 const std::vector<t_struct*>& get_structs() const { return structs_; }
100 const std::vector<t_struct*>& get_xceptions() const { return xceptions_; }
101 const std::vector<t_struct*>& get_objects() const { return objects_; }
102 const std::vector<t_service*>& get_services() const { return services_; }
103 const std::map<std::string, std::string>& get_namespaces() const { return namespaces_; }
Mark Slee31985722006-05-24 21:45:31 +0000104
Mark Sleef0712dc2006-10-25 19:03:57 +0000105 // Program elements
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100106 void add_typedef(t_typedef* td) { typedefs_.push_back(td); }
107 void add_enum(t_enum* te) { enums_.push_back(te); }
108 void add_const(t_const* tc) { consts_.push_back(tc); }
109 void add_struct(t_struct* ts) {
110 objects_.push_back(ts);
111 structs_.push_back(ts);
112 }
113 void add_xception(t_struct* tx) {
114 objects_.push_back(tx);
115 xceptions_.push_back(tx);
116 }
117 void add_service(t_service* ts) { services_.push_back(ts); }
Mark Slee31985722006-05-24 21:45:31 +0000118
Mark Sleef0712dc2006-10-25 19:03:57 +0000119 // Programs to include
120 const std::vector<t_program*>& get_includes() const { return includes_; }
Mark Sleee8540632006-05-30 09:24:40 +0000121
Bryan Duxburybdca9f62011-03-01 19:53:07 +0000122 void set_out_path(std::string out_path, bool out_path_is_absolute) {
dweatherford65b70752007-10-31 02:18:14 +0000123 out_path_ = out_path;
Bryan Duxburybdca9f62011-03-01 19:53:07 +0000124 out_path_is_absolute_ = out_path_is_absolute;
dweatherford65b70752007-10-31 02:18:14 +0000125 // Ensure that it ends with a trailing '/' (or '\' for windows machines)
126 char c = out_path_.at(out_path_.size() - 1);
127 if (!(c == '/' || c == '\\')) {
128 out_path_.push_back('/');
129 }
130 }
131
Roger Meierba406d32013-07-15 22:41:34 +0200132 // Typename collision detection
133 /**
134 * Search for typename collisions
135 * @param t the type to test for collisions
136 * @return true if a certain collision was found, otherwise false
137 */
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100138 bool is_unique_typename(t_type* t) {
Konrad Grochowski3b5dacb2014-11-24 10:55:31 +0100139 int occurrences = program_typename_count(this, t);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100140 for (std::vector<t_program*>::iterator it = includes_.begin(); it != includes_.end(); ++it) {
Konrad Grochowski3b5dacb2014-11-24 10:55:31 +0100141 occurrences += program_typename_count(*it, t);
Roger Meierba406d32013-07-15 22:41:34 +0200142 }
Konrad Grochowski3b5dacb2014-11-24 10:55:31 +0100143 return 0 == occurrences;
Roger Meierba406d32013-07-15 22:41:34 +0200144 }
145
146 /**
147 * Search all type collections for duplicate typenames
148 * @param prog the program to search
149 * @param t the type to test for collisions
150 * @return the number of certain typename collisions
151 */
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100152 int program_typename_count(t_program* prog, t_type* t) {
Konrad Grochowski3b5dacb2014-11-24 10:55:31 +0100153 int occurrences = 0;
154 occurrences += collection_typename_count(prog, prog->typedefs_, t);
155 occurrences += collection_typename_count(prog, prog->enums_, t);
156 occurrences += collection_typename_count(prog, prog->objects_, t);
157 occurrences += collection_typename_count(prog, prog->services_, t);
158 return occurrences;
Roger Meierba406d32013-07-15 22:41:34 +0200159 }
160
161 /**
162 * Search a type collection for duplicate typenames
163 * @param prog the program to search
164 * @param type_collection the type collection to search
165 * @param t the type to test for collisions
166 * @return the number of certain typename collisions
167 */
168 template <class T>
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100169 int collection_typename_count(t_program* prog, T type_collection, t_type* t) {
Konrad Grochowski3b5dacb2014-11-24 10:55:31 +0100170 int occurrences = 0;
Roger Meierba406d32013-07-15 22:41:34 +0200171 for (typename T::iterator it = type_collection.begin(); it != type_collection.end(); ++it)
172 if (t != *it && 0 == t->get_name().compare((*it)->get_name()) && is_common_namespace(prog, t))
Konrad Grochowski3b5dacb2014-11-24 10:55:31 +0100173 ++occurrences;
174 return occurrences;
Roger Meierba406d32013-07-15 22:41:34 +0200175 }
176
177 /**
178 * Determine whether identical typenames will collide based on namespaces.
179 *
180 * Because we do not know which languages the user will generate code for,
181 * collisions within programs (IDL files) having namespace declarations can be
182 * difficult to determine. Only guaranteed collisions return true (cause an error).
183 * Possible collisions involving explicit namespace declarations produce a warning.
184 * Other possible collisions go unreported.
185 * @param prog the program containing the preexisting typename
186 * @param t the type containing the typename match
187 * @return true if a collision within namespaces is found, otherwise false
188 */
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100189 bool is_common_namespace(t_program* prog, t_type* t) {
190 // Case 1: Typenames are in the same program [collision]
Roger Meierba406d32013-07-15 22:41:34 +0200191 if (prog == t->get_program()) {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100192 pwarning(1,
193 "Duplicate typename %s found in %s",
194 t->get_name().c_str(),
195 t->get_program()->get_name().c_str());
Roger Meierba406d32013-07-15 22:41:34 +0200196 return true;
197 }
198
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100199 // Case 2: Both programs have identical namespace scope/name declarations [collision]
Roger Meierba406d32013-07-15 22:41:34 +0200200 bool match = true;
201 for (std::map<std::string, std::string>::iterator it = prog->namespaces_.begin();
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100202 it != prog->namespaces_.end();
203 ++it) {
Roger Meierba406d32013-07-15 22:41:34 +0200204 if (0 == it->second.compare(t->get_program()->get_namespace(it->first))) {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100205 pwarning(1,
206 "Duplicate typename %s found in %s,%s,%s and %s,%s,%s [file,scope,ns]",
Roger Meierba406d32013-07-15 22:41:34 +0200207 t->get_name().c_str(),
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100208 t->get_program()->get_name().c_str(),
209 it->first.c_str(),
210 it->second.c_str(),
211 prog->get_name().c_str(),
212 it->first.c_str(),
213 it->second.c_str());
Roger Meierba406d32013-07-15 22:41:34 +0200214 } else {
215 match = false;
216 }
217 }
218 for (std::map<std::string, std::string>::iterator it = t->get_program()->namespaces_.begin();
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100219 it != t->get_program()->namespaces_.end();
220 ++it) {
Roger Meierba406d32013-07-15 22:41:34 +0200221 if (0 == it->second.compare(prog->get_namespace(it->first))) {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100222 pwarning(1,
223 "Duplicate typename %s found in %s,%s,%s and %s,%s,%s [file,scope,ns]",
Roger Meierba406d32013-07-15 22:41:34 +0200224 t->get_name().c_str(),
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100225 t->get_program()->get_name().c_str(),
226 it->first.c_str(),
227 it->second.c_str(),
228 prog->get_name().c_str(),
229 it->first.c_str(),
230 it->second.c_str());
Roger Meierba406d32013-07-15 22:41:34 +0200231 } else {
232 match = false;
233 }
234 }
235 if (0 == prog->namespaces_.size() && 0 == t->get_program()->namespaces_.size()) {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100236 pwarning(1,
237 "Duplicate typename %s found in %s and %s",
238 t->get_name().c_str(),
239 t->get_program()->get_name().c_str(),
240 prog->get_name().c_str());
Roger Meierba406d32013-07-15 22:41:34 +0200241 }
242 return match;
243 }
244
Mark Sleef0712dc2006-10-25 19:03:57 +0000245 // Scoping and namespacing
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100246 void set_namespace(std::string name) { namespace_ = name; }
Mark Slee9cb7c612006-09-01 22:17:45 +0000247
Mark Sleef0712dc2006-10-25 19:03:57 +0000248 // Scope accessor
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100249 t_scope* scope() const { return scope_; }
Mark Sleef5377b32006-10-10 01:42:59 +0000250
Mark Sleef0712dc2006-10-25 19:03:57 +0000251 // Includes
252
kholst76f2c882008-01-16 02:47:41 +0000253 void add_include(std::string path, std::string include_site) {
254 t_program* program = new t_program(path);
255
256 // include prefix for this program is the site at which it was included
257 // (minus the filename)
258 std::string include_prefix;
259 std::string::size_type last_slash = std::string::npos;
260 if ((last_slash = include_site.rfind("/")) != std::string::npos) {
261 include_prefix = include_site.substr(0, last_slash);
262 }
263
264 program->set_include_prefix(include_prefix);
265 includes_.push_back(program);
Mark Sleee8540632006-05-30 09:24:40 +0000266 }
Mark Sleef5377b32006-10-10 01:42:59 +0000267
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100268 std::vector<t_program*>& get_includes() { return includes_; }
Mark Sleef5377b32006-10-10 01:42:59 +0000269
kholst76f2c882008-01-16 02:47:41 +0000270 void set_include_prefix(std::string include_prefix) {
271 include_prefix_ = include_prefix;
272
273 // this is intended to be a directory; add a trailing slash if necessary
Jim King9de9b1f2015-04-30 16:03:34 -0400274 std::string::size_type len = include_prefix_.size();
kholst76f2c882008-01-16 02:47:41 +0000275 if (len > 0 && include_prefix_[len - 1] != '/') {
276 include_prefix_ += '/';
277 }
278 }
279
David Reiss79eca142008-02-27 01:55:13 +0000280 // Language neutral namespace / packaging
281 void set_namespace(std::string language, std::string name_space) {
Bryan Duxburybbff4a82010-09-03 20:36:02 +0000282 if (language != "*") {
283 size_t sub_index = language.find('.');
284 std::string base_language = language.substr(0, sub_index);
285 std::string sub_namespace;
Bryan Duxbury681f5ea2010-08-20 16:42:04 +0000286
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100287 if (base_language == "smalltalk") {
Bryan Duxburybbff4a82010-09-03 20:36:02 +0000288 pwarning(1, "Namespace 'smalltalk' is deprecated. Use 'st' instead");
289 base_language = "st";
290 }
Bryan Duxbury4d8a9cd2010-08-30 17:09:58 +0000291
Bryan Duxburybbff4a82010-09-03 20:36:02 +0000292 t_generator_registry::gen_map_t my_copy = t_generator_registry::get_generator_map();
Bryan Duxburye0ac3ab2010-07-29 16:24:41 +0000293
Bryan Duxburybbff4a82010-09-03 20:36:02 +0000294 t_generator_registry::gen_map_t::iterator it;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100295 it = my_copy.find(base_language);
Bryan Duxburye0ac3ab2010-07-29 16:24:41 +0000296
Bryan Duxburybbff4a82010-09-03 20:36:02 +0000297 if (it == my_copy.end()) {
Henrique Mendoncaffb031d2012-09-24 18:36:16 +0000298 std::string warning = "No generator named '" + base_language + "' could be found!";
299 pwarning(1, warning.c_str());
300 } else {
301 if (sub_index != std::string::npos) {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100302 std::string sub_namespace = language.substr(sub_index + 1);
303 if (!it->second->is_valid_namespace(sub_namespace)) {
304 std::string warning = base_language + " generator does not accept '" + sub_namespace
305 + "' as sub-namespace!";
Henrique Mendonça8ad13a32013-05-16 21:26:20 +0200306 pwarning(1, warning.c_str());
Henrique Mendoncaffb031d2012-09-24 18:36:16 +0000307 }
Bryan Duxburybbff4a82010-09-03 20:36:02 +0000308 }
Bryan Duxbury681f5ea2010-08-20 16:42:04 +0000309 }
David Reisse3ba3492010-08-26 21:49:45 +0000310 }
Bryan Duxbury681f5ea2010-08-20 16:42:04 +0000311
David Reiss79eca142008-02-27 01:55:13 +0000312 namespaces_[language] = name_space;
313 }
314
315 std::string get_namespace(std::string language) const {
David Reissfb790d72010-09-02 16:41:45 +0000316 std::map<std::string, std::string>::const_iterator iter;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100317 if ((iter = namespaces_.find(language)) != namespaces_.end()
318 || (iter = namespaces_.find("*")) != namespaces_.end()) {
David Reissfb790d72010-09-02 16:41:45 +0000319 return iter->second;
David Reiss79eca142008-02-27 01:55:13 +0000320 }
David Reissfb790d72010-09-02 16:41:45 +0000321 return std::string();
David Reiss79eca142008-02-27 01:55:13 +0000322 }
323
Mark Sleef0712dc2006-10-25 19:03:57 +0000324 // Language specific namespace / packaging
325
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100326 void add_cpp_include(std::string path) { cpp_includes_.push_back(path); }
Mark Sleef0712dc2006-10-25 19:03:57 +0000327
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100328 const std::vector<std::string>& get_cpp_includes() { return cpp_includes_; }
Mark Sleef0712dc2006-10-25 19:03:57 +0000329
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100330 void add_c_include(std::string path) { c_includes_.push_back(path); }
Roger Meier213a6642010-10-27 12:30:11 +0000331
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100332 const std::vector<std::string>& get_c_includes() { return c_includes_; }
Roger Meier213a6642010-10-27 12:30:11 +0000333
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100334private:
Mark Sleef0712dc2006-10-25 19:03:57 +0000335 // File path
336 std::string path_;
Mark Slee9cb7c612006-09-01 22:17:45 +0000337
Mark Slee31985722006-05-24 21:45:31 +0000338 // Name
339 std::string name_;
340
dweatherford65b70752007-10-31 02:18:14 +0000341 // Output directory
342 std::string out_path_;
343
Bryan Duxburybdca9f62011-03-01 19:53:07 +0000344 // Output directory is absolute location for generated source (no gen-*)
345 bool out_path_is_absolute_;
346
Mark Slee9cb7c612006-09-01 22:17:45 +0000347 // Namespace
348 std::string namespace_;
349
Mark Sleef0712dc2006-10-25 19:03:57 +0000350 // Included programs
351 std::vector<t_program*> includes_;
Mark Sleee8540632006-05-30 09:24:40 +0000352
kholst76f2c882008-01-16 02:47:41 +0000353 // Include prefix for this program, if any
354 std::string include_prefix_;
355
Mark Sleef0712dc2006-10-25 19:03:57 +0000356 // Identifier lookup scope
357 t_scope* scope_;
Mark Sleee8540632006-05-30 09:24:40 +0000358
Mark Sleef0712dc2006-10-25 19:03:57 +0000359 // Components to generate code for
360 std::vector<t_typedef*> typedefs_;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100361 std::vector<t_enum*> enums_;
362 std::vector<t_const*> consts_;
363 std::vector<t_struct*> objects_;
364 std::vector<t_struct*> structs_;
365 std::vector<t_struct*> xceptions_;
Mark Sleef0712dc2006-10-25 19:03:57 +0000366 std::vector<t_service*> services_;
367
David Reiss79eca142008-02-27 01:55:13 +0000368 // Dynamic namespaces
369 std::map<std::string, std::string> namespaces_;
370
Mark Sleef0712dc2006-10-25 19:03:57 +0000371 // C++ extra includes
372 std::vector<std::string> cpp_includes_;
373
Roger Meier213a6642010-10-27 12:30:11 +0000374 // C extra includes
375 std::vector<std::string> c_includes_;
Mark Slee31985722006-05-24 21:45:31 +0000376};
377
378#endif