]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
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 | */ | |
19 | ||
20 | #include "thrift/generate/t_generator.h" | |
21 | using namespace std; | |
22 | ||
23 | /** | |
24 | * Top level program generation function. Calls the generator subclass methods | |
25 | * for preparing file streams etc. then iterates over all the parts of the | |
26 | * program to perform the correct actions. | |
27 | * | |
28 | * @param program The thrift program to compile into C++ source | |
29 | */ | |
30 | void t_generator::generate_program() { | |
31 | // Initialize the generator | |
32 | init_generator(); | |
33 | ||
34 | // Generate enums | |
35 | vector<t_enum*> enums = program_->get_enums(); | |
36 | vector<t_enum*>::iterator en_iter; | |
37 | for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) { | |
38 | generate_enum(*en_iter); | |
39 | } | |
40 | ||
41 | // Generate typedefs | |
42 | vector<t_typedef*> typedefs = program_->get_typedefs(); | |
43 | vector<t_typedef*>::iterator td_iter; | |
44 | for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) { | |
45 | generate_typedef(*td_iter); | |
46 | } | |
47 | ||
48 | // Generate structs, exceptions, and unions in declared order | |
49 | vector<t_struct*> objects = program_->get_objects(); | |
50 | ||
51 | vector<t_struct*>::iterator o_iter; | |
52 | for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) { | |
53 | generate_forward_declaration(*o_iter); | |
54 | } | |
55 | for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) { | |
56 | if ((*o_iter)->is_xception()) { | |
57 | generate_xception(*o_iter); | |
58 | } else { | |
59 | generate_struct(*o_iter); | |
60 | } | |
61 | } | |
62 | ||
63 | // Generate constants | |
64 | vector<t_const*> consts = program_->get_consts(); | |
65 | generate_consts(consts); | |
66 | ||
67 | // Generate services | |
68 | vector<t_service*> services = program_->get_services(); | |
69 | vector<t_service*>::iterator sv_iter; | |
70 | for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) { | |
71 | service_name_ = get_service_name(*sv_iter); | |
72 | generate_service(*sv_iter); | |
73 | } | |
74 | ||
75 | // Close the generator | |
76 | close_generator(); | |
77 | } | |
78 | ||
79 | std::set<std::string> t_generator::lang_keywords() const { | |
80 | std::string keywords[] = { "BEGIN", "END", "__CLASS__", "__DIR__", "__FILE__", "__FUNCTION__", | |
81 | "__LINE__", "__METHOD__", "__NAMESPACE__", "abstract", "alias", "and", "args", "as", | |
82 | "assert", "begin", "break", "case", "catch", "class", "clone", "continue", "declare", | |
83 | "def", "default", "del", "delete", "do", "dynamic", "elif", "else", "elseif", "elsif", | |
84 | "end", "enddeclare", "endfor", "endforeach", "endif", "endswitch", "endwhile", "ensure", | |
85 | "except", "exec", "finally", "float", "for", "foreach", "from", "function", "global", | |
86 | "goto", "if", "implements", "import", "in", "inline", "instanceof", "interface", "is", | |
87 | "lambda", "module", "native", "new", "next", "nil", "not", "or", "package", "pass", | |
88 | "public", "print", "private", "protected", "raise", "redo", "rescue", "retry", "register", | |
89 | "return", "self", "sizeof", "static", "super", "switch", "synchronized", "then", "this", | |
90 | "throw", "transient", "try", "undef", "unless", "unsigned", "until", "use", "var", | |
91 | "virtual", "volatile", "when", "while", "with", "xor", "yield" }; | |
92 | return std::set<std::string>(keywords, keywords + sizeof(keywords)/sizeof(keywords[0]) ); | |
93 | } | |
94 | ||
95 | void t_generator::validate_input() const { | |
96 | validate(program_->get_enums()); | |
97 | validate(program_->get_typedefs()); | |
98 | validate(program_->get_objects()); | |
99 | validate(program_->get_consts()); | |
100 | validate(program_->get_services()); | |
101 | } | |
102 | ||
103 | template <typename T> | |
104 | void t_generator::validate(const vector<T>& list) const{ | |
105 | typename vector<T>::const_iterator it; | |
106 | for(it=list.begin(); it != list.end(); ++it) { | |
107 | validate(*it); | |
108 | } | |
109 | } | |
110 | ||
111 | void t_generator::validate(t_function const* f) const { | |
112 | validate_id(f->get_name()); | |
113 | validate(f->get_arglist()); | |
114 | validate(f->get_xceptions()); | |
115 | } | |
116 | ||
117 | void t_generator::validate(t_service const* s) const { | |
118 | validate_id(s->get_name()); | |
119 | validate(s->get_functions()); | |
120 | } | |
121 | ||
122 | void t_generator::validate(t_enum const* en) const { | |
123 | validate_id(en->get_name()); | |
124 | validate(en->get_constants()); | |
125 | } | |
126 | void t_generator::validate(t_struct const* s) const { | |
127 | validate_id(s->get_name()); | |
128 | validate(s->get_members()); | |
129 | } | |
130 | ||
131 | void t_generator::validate(t_enum_value const* en_val) const { | |
132 | validate_id(en_val->get_name()); | |
133 | } | |
134 | void t_generator::validate(t_typedef const* td) const { | |
135 | validate_id(td->get_name()); | |
136 | } | |
137 | void t_generator::validate(t_const const* c) const { | |
138 | validate_id(c->get_name()); | |
139 | } | |
140 | void t_generator::validate(t_field const* f) const { | |
141 | validate_id(f->get_name()); | |
142 | } | |
143 | ||
144 | void t_generator::validate_id(const string& id) const { | |
145 | if (keywords_.find(id) != keywords_.end()) { | |
146 | failure("Cannot use reserved language keyword: \"%s\"", id.c_str()); | |
147 | } | |
148 | } | |
149 | ||
150 | string t_generator::escape_string(const string& in) const { | |
151 | string result = ""; | |
152 | for (string::const_iterator it = in.begin(); it < in.end(); it++) { | |
153 | std::map<char, std::string>::const_iterator res = escape_.find(*it); | |
154 | if (res != escape_.end()) { | |
155 | result.append(res->second); | |
156 | } else { | |
157 | result.push_back(*it); | |
158 | } | |
159 | } | |
160 | return result; | |
161 | } | |
162 | ||
163 | void t_generator::generate_consts(vector<t_const*> consts) { | |
164 | vector<t_const*>::iterator c_iter; | |
165 | for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { | |
166 | generate_const(*c_iter); | |
167 | } | |
168 | } | |
169 | ||
170 | void t_generator::generate_docstring_comment(ostream& out, | |
171 | const string& comment_start, | |
172 | const string& line_prefix, | |
173 | const string& contents, | |
174 | const string& comment_end) { | |
175 | if (!comment_start.empty()) | |
176 | indent(out) << comment_start; | |
177 | stringstream docs(contents, ios_base::in); | |
178 | while (!(docs.eof() || docs.fail())) { | |
179 | char line[1024]; | |
180 | docs.getline(line, 1024); | |
181 | ||
182 | if (strlen(line) > 0) { | |
183 | indent(out) << line_prefix << line << std::endl; | |
184 | } else if (line_prefix.empty()){ | |
185 | out << std::endl; | |
186 | } else if(!docs.eof()) { | |
187 | indent(out) << line_prefix << std::endl; | |
188 | } | |
189 | } | |
190 | if (!comment_end.empty()) | |
191 | indent(out) << comment_end; | |
192 | } | |
193 | ||
194 | void t_generator_registry::register_generator(t_generator_factory* factory) { | |
195 | gen_map_t& the_map = get_generator_map(); | |
196 | if (the_map.find(factory->get_short_name()) != the_map.end()) { | |
197 | failure("Duplicate generators for language \"%s\"!\n", factory->get_short_name().c_str()); | |
198 | } | |
199 | the_map[factory->get_short_name()] = factory; | |
200 | } | |
201 | ||
202 | void t_generator::parse_options(const string& options, | |
203 | string& language, | |
204 | map<string, string>& parsed_options) { | |
205 | string::size_type colon = options.find(':'); | |
206 | language = options.substr(0, colon); | |
207 | ||
208 | if (colon != string::npos) { | |
209 | string::size_type pos = colon + 1; | |
210 | while (pos != string::npos && pos < options.size()) { | |
211 | string::size_type next_pos = options.find(',', pos); | |
212 | string option = options.substr(pos, next_pos - pos); | |
213 | pos = ((next_pos == string::npos) ? next_pos : next_pos + 1); | |
214 | ||
215 | string::size_type separator = option.find('='); | |
216 | string key, value; | |
217 | if (separator == string::npos) { | |
218 | key = option; | |
219 | value = ""; | |
220 | } else { | |
221 | key = option.substr(0, separator); | |
222 | value = option.substr(separator + 1); | |
223 | } | |
224 | ||
225 | parsed_options[key] = value; | |
226 | } | |
227 | } | |
228 | } | |
229 | ||
230 | t_generator* t_generator_registry::get_generator(t_program* program, | |
231 | const string& language, | |
232 | const map<string, string>& parsed_options, | |
233 | const std::string& options) { | |
234 | gen_map_t& the_map = get_generator_map(); | |
235 | gen_map_t::iterator iter = the_map.find(language); | |
236 | ||
237 | if (iter == the_map.end()) { | |
238 | return NULL; | |
239 | } | |
240 | ||
241 | return iter->second->get_generator(program, parsed_options, options); | |
242 | } | |
243 | ||
244 | t_generator* t_generator_registry::get_generator(t_program* program, const string& options) { | |
245 | string language; | |
246 | map<string, string> parsed_options; | |
247 | t_generator::parse_options(options, language, parsed_options); | |
248 | return get_generator(program, language, parsed_options, options); | |
249 | } | |
250 | ||
251 | t_generator_registry::gen_map_t& t_generator_registry::get_generator_map() { | |
252 | // http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12 | |
253 | static gen_map_t* the_map = new gen_map_t(); | |
254 | return *the_map; | |
255 | } | |
256 | ||
257 | t_generator_factory::t_generator_factory(const std::string& short_name, | |
258 | const std::string& long_name, | |
259 | const std::string& documentation) | |
260 | : short_name_(short_name), long_name_(long_name), documentation_(documentation) { | |
261 | t_generator_registry::register_generator(this); | |
262 | } |