1 /******************************************************************************
3 * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
5 * This program is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU General Public License *
7 * as published by the Free Software Foundation; either version 2 *
8 * of the License, or (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the Free Software Foundation *
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
18 ******************************************************************************/
20 #include "classcompiler.h"
27 using namespace icinga;
29 ClassCompiler::ClassCompiler(const std::string& path, std::istream *input)
30 : m_Path(path), m_Input(input)
35 ClassCompiler::~ClassCompiler(void)
40 std::string ClassCompiler::GetPath(void) const
45 void *ClassCompiler::GetScanner(void)
50 size_t ClassCompiler::ReadInput(char *buffer, size_t max_size)
52 m_Input->read(buffer, max_size);
53 return static_cast<size_t>(m_Input->gcount());
56 void ClassCompiler::HandleInclude(const std::string& path, const ClassDebugInfo& locp)
58 std::cout << "#include \"" << path << "\"" << std::endl << std::endl;
61 void ClassCompiler::HandleAngleInclude(const std::string& path, const ClassDebugInfo& locp)
63 std::cout << "#include <" << path << ">" << std::endl << std::endl;
66 void ClassCompiler::HandleNamespaceBegin(const std::string& name, const ClassDebugInfo& locp)
68 std::cout << "namespace " << name << std::endl
69 << "{" << std::endl << std::endl;
72 void ClassCompiler::HandleNamespaceEnd(const ClassDebugInfo& locp)
74 std::cout << "}" << std::endl;
77 void ClassCompiler::HandleCode(const std::string& code, const ClassDebugInfo& locp)
79 std::cout << code << std::endl;
82 unsigned long ClassCompiler::SDBM(const std::string& str, size_t len = std::string::npos)
84 unsigned long hash = 0;
87 std::string::const_iterator it;
89 for (it = str.begin(); it != str.end(); it++) {
95 hash = c + (hash << 6) + (hash << 16) - hash;
103 void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo& locp)
105 std::vector<Field>::const_iterator it;
107 /* forward declaration */
108 if (klass.Name.find_first_of(':') == std::string::npos)
109 std::cout << "class " << klass.Name << ";" << std::endl << std::endl;
112 std::cout << "template<>" << std::endl
113 << "class TypeImpl<" << klass.Name << ">"
114 << " : public Type" << std::endl
116 << "public:" << std::endl;
119 std::cout << "\t" << "virtual String GetName(void) const" << std::endl
120 << "\t" << "{" << std::endl
121 << "\t\t" << "return \"" << klass.Name << "\";" << std::endl
122 << "\t" << "}" << std::endl << std::endl;
125 std::cout << "\t" << "virtual int GetAttributes(void) const" << std::endl
126 << "\t" << "{" << std::endl
127 << "\t\t" << "return " << klass.Attributes << ";" << std::endl
128 << "\t" << "}" << std::endl << std::endl;
131 std::cout << "\t" << "virtual const Type *GetBaseType(void) const" << std::endl
132 << "\t" << "{" << std::endl;
134 std::cout << "\t\t" << "return ";
136 if (!klass.Parent.empty())
137 std::cout << "Type::GetByName(\"" << klass.Parent << "\")";
141 std::cout << ";" << std::endl
142 << "\t" << "}" << std::endl << std::endl;
145 std::cout << "\t" << "virtual int GetFieldId(const String& name) const" << std::endl
146 << "\t" << "{" << std::endl
147 << "\t\t" << "return StaticGetFieldId(name);" << std::endl
148 << "\t" << "}" << std::endl << std::endl;
150 /* StaticGetFieldId */
151 std::cout << "\t" << "static int StaticGetFieldId(const String& name)" << std::endl
152 << "\t" << "{" << std::endl;
154 if (!klass.Fields.empty()) {
155 std::cout << "\t\t" << "int offset = ";
157 if (!klass.Parent.empty())
158 std::cout << "TypeImpl<" << klass.Parent << ">::StaticGetFieldCount()";
162 std::cout << ";" << std::endl << std::endl;
165 std::map<int, std::vector<std::pair<int, std::string> > > jumptable;
167 int hlen = 0, collisions = 0;
176 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
177 int hash = static_cast<int>(SDBM(it->Name, hlen));
178 jumptable[hash].push_back(std::make_pair(num, it->Name));
181 if (jumptable[hash].size() > 1)
184 } while (collisions >= 5 && hlen < 8);
186 if (!klass.Fields.empty()) {
187 std::cout << "\t\tswitch (static_cast<int>(Utility::SDBM(name, " << hlen << "))) {" << std::endl;
189 std::map<int, std::vector<std::pair<int, std::string> > >::const_iterator itj;
191 for (itj = jumptable.begin(); itj != jumptable.end(); itj++) {
192 std::cout << "\t\t\tcase " << itj->first << ":" << std::endl;
194 std::vector<std::pair<int, std::string> >::const_iterator itf;
196 for (itf = itj->second.begin(); itf != itj->second.end(); itf++) {
197 std::cout << "\t\t\t\t" << "if (name == \"" << itf->second << "\")" << std::endl
198 << "\t\t\t\t\t" << "return offset + " << itf->first << ";" << std::endl;
201 std::cout << std::endl
202 << "\t\t\t\tbreak;" << std::endl;
205 std::cout << "\t\t}" << std::endl;
208 std::cout << std::endl
209 << "\t\t" << "return ";
211 if (!klass.Parent.empty())
212 std::cout << "TypeImpl<" << klass.Parent << ">::StaticGetFieldId(name)";
216 std::cout << ";" << std::endl
217 << "\t" << "}" << std::endl << std::endl;
220 std::cout << "\t" << "virtual Field GetFieldInfo(int id) const" << std::endl
221 << "\t" << "{" << std::endl
222 << "\t\t" << "return StaticGetFieldInfo(id);" << std::endl
223 << "\t" << "}" << std::endl << std::endl;
225 /* StaticGetFieldInfo */
226 std::cout << "\t" << "static Field StaticGetFieldInfo(int id)" << std::endl
227 << "\t" << "{" << std::endl;
229 if (!klass.Parent.empty())
230 std::cout << "\t\t" << "int real_id = id - " << "TypeImpl<" << klass.Parent << ">::StaticGetFieldCount();" << std::endl
231 << "\t\t" << "if (real_id < 0) { return " << "TypeImpl<" << klass.Parent << ">::StaticGetFieldInfo(id); }" << std::endl;
233 if (klass.Fields.size() > 0) {
234 std::cout << "\t\t" << "switch (";
236 if (!klass.Parent.empty())
237 std::cout << "real_id";
241 std::cout << ") {" << std::endl;
244 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
245 std::cout << "\t\t\t" << "case " << num << ":" << std::endl
246 << "\t\t\t\t" << "return Field(" << num << ", \"" << it->Name << "\", " << it->Attributes << ");" << std::endl;
250 std::cout << "\t\t\t" << "default:" << std::endl
254 std::cout << "\t\t" << "throw std::runtime_error(\"Invalid field ID.\");" << std::endl;
256 if (klass.Fields.size() > 0)
257 std::cout << "\t\t" << "}" << std::endl;
259 std::cout << "\t" << "}" << std::endl << std::endl;
262 std::cout << "\t" << "virtual int GetFieldCount(void) const" << std::endl
263 << "\t" << "{" << std::endl
264 << "\t\t" << "return StaticGetFieldCount();" << std::endl
265 << "\t" << "}" << std::endl << std::endl;
267 /* StaticGetFieldCount */
268 std::cout << "\t" << "static int StaticGetFieldCount(void)" << std::endl
269 << "\t" << "{" << std::endl
270 << "\t\t" << "return " << klass.Fields.size();
272 if (!klass.Parent.empty())
273 std::cout << " + " << "TypeImpl<" << klass.Parent << ">::StaticGetFieldCount()";
275 std::cout << ";" << std::endl
276 << "\t" << "}" << std::endl << std::endl;
278 std::cout << "};" << std::endl << std::endl;
281 std::cout << "template<>" << std::endl
282 << "class ObjectImpl<" << klass.Name << ">"
283 << " : public " << (klass.Parent.empty() ? "Object" : klass.Parent) << std::endl
285 << "public:" << std::endl
286 << "\t" << "DECLARE_PTR_TYPEDEFS(ObjectImpl<" << klass.Name << ">);" << std::endl << std::endl;
288 /* GetReflectionType */
289 std::cout << "\t" << "virtual const Type *GetReflectionType(void) const" << std::endl
290 << "\t" << "{" << std::endl
291 << "\t\t" << "return Type::GetByName(\"" << klass.Name << "\");" << std::endl
292 << "\t" << "}" << std::endl << std::endl;
294 if (!klass.Fields.empty()) {
296 std::cout << "public:" << std::endl
297 << "\t" << "ObjectImpl<" << klass.Name << ">(void)" << std::endl
298 << "\t" << "{" << std::endl;
300 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
301 std::cout << "\t\t" << "Set" << it->GetFriendlyName() << "(" << "GetDefault" << it->GetFriendlyName() << "());" << std::endl;
304 std::cout << "\t" << "}" << std::endl << std::endl;
307 std::cout << "protected:" << std::endl
308 << "\t" << "virtual void SetField(int id, const Value& value)" << std::endl
309 << "\t" << "{" << std::endl;
311 if (!klass.Parent.empty())
312 std::cout << "\t\t" << "int real_id = id - TypeImpl<" << klass.Parent << ">::StaticGetFieldCount(); " << std::endl
313 << "\t\t" << "if (real_id < 0) { " << klass.Parent << "::SetField(id, value); return; }" << std::endl;
315 std::cout << "\t\t" << "switch (";
317 if (!klass.Parent.empty())
318 std::cout << "real_id";
322 std::cout << ") {" << std::endl;
325 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
326 std::cout << "\t\t\t" << "case " << num << ":" << std::endl
327 << "\t\t\t\t" << "Set" << it->GetFriendlyName() << "(";
329 if (it->Attributes & FAEnum)
330 std::cout << "static_cast<" << it->Type << ">(static_cast<int>(";
332 std::cout << "value";
334 if (it->Attributes & FAEnum)
337 std::cout << ");" << std::endl
338 << "\t\t\t\t" << "break;" << std::endl;
342 std::cout << "\t\t\t" << "default:" << std::endl
343 << "\t\t\t\t" << "throw std::runtime_error(\"Invalid field ID.\");" << std::endl
344 << "\t\t" << "}" << std::endl;
346 std::cout << "\t" << "}" << std::endl << std::endl;
349 std::cout << "protected:" << std::endl
350 << "\t" << "virtual Value GetField(int id) const" << std::endl
351 << "\t" << "{" << std::endl;
353 if (!klass.Parent.empty())
354 std::cout << "\t\t" << "int real_id = id - TypeImpl<" << klass.Parent << ">::StaticGetFieldCount(); " << std::endl
355 << "\t\t" << "if (real_id < 0) { return " << klass.Parent << "::GetField(id); }" << std::endl;
357 std::cout << "\t\t" << "switch (";
359 if (!klass.Parent.empty())
360 std::cout << "real_id";
364 std::cout << ") {" << std::endl;
367 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
368 std::cout << "\t\t\t" << "case " << num << ":" << std::endl
369 << "\t\t\t\t" << "return Get" << it->GetFriendlyName() << "();" << std::endl;
373 std::cout << "\t\t\t" << "default:" << std::endl
374 << "\t\t\t\t" << "throw std::runtime_error(\"Invalid field ID.\");" << std::endl
375 << "\t\t" << "}" << std::endl;
377 std::cout << "\t" << "}" << std::endl << std::endl;
380 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
383 if (it->Attributes & FAGetProtected)
388 std::cout << prot << ":" << std::endl
389 << "\t" << it->Type << " Get" << it->GetFriendlyName() << "(void) const" << std::endl
390 << "\t" << "{" << std::endl;
392 if (it->GetAccessor.empty())
393 std::cout << "\t\t" << "return m_" << it->GetFriendlyName() << ";" << std::endl;
395 std::cout << it->GetAccessor << std::endl;
397 std::cout << "\t" << "}" << std::endl << std::endl;
401 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
404 if (it->Attributes & FASetProtected)
406 else if (it->Attributes & FAConfig)
411 std::cout << prot << ":" << std::endl
412 << "\t" << "void Set" << it->GetFriendlyName() << "(const " << it->Type << "& value)" << std::endl
413 << "\t" << "{" << std::endl;
415 if (it->SetAccessor.empty())
416 std::cout << "\t\t" << "m_" << it->GetFriendlyName() << " = value;" << std::endl;
418 std::cout << it->SetAccessor << std::endl;
420 std::cout << "\t" << "}" << std::endl << std::endl;
424 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
427 std::cout << "private:" << std::endl
428 << "\t" << it->Type << " GetDefault" << it->GetFriendlyName() << "(void) const" << std::endl
429 << "\t" << "{" << std::endl;
431 if (it->DefaultAccessor.empty())
432 std::cout << "\t\t" << "return " << it->Type << "();" << std::endl;
434 std::cout << it->DefaultAccessor << std::endl;
436 std::cout << "\t" << "}" << std::endl;
439 /* instance variables */
440 std::cout << "private:" << std::endl;
442 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
443 std::cout << "\t" << it->Type << " m_" << it->GetFriendlyName() << ";" << std::endl;
447 std::cout << "};" << std::endl << std::endl;
450 if (klass.Attributes & TAAbstract) {
451 std::cout << "template<>" << std::endl
452 << "struct FactoryHelper<" << klass.Name << ">" << std::endl
454 << "\t" << "Type::Factory GetFactory(void)" << std::endl
455 << "\t" << "{" << std::endl
456 << "\t\t" << "return Type::Factory();"
458 << "};" << std::endl << std::endl;
462 void ClassCompiler::CompileFile(const std::string& path)
464 std::ifstream stream;
465 stream.open(path.c_str(), std::ifstream::in);
468 throw std::invalid_argument("Could not open config file: " + path);
470 return CompileStream(path, &stream);
473 void ClassCompiler::CompileStream(const std::string& path, std::istream *stream)
475 stream->exceptions(std::istream::badbit);
477 std::cout << "#include \"base/object.h\"" << std::endl
478 << "#include \"base/type.h\"" << std::endl
479 << "#include \"base/debug.h\"" << std::endl
480 << "#include \"base/value.h\"" << std::endl
481 << "#include \"base/array.h\"" << std::endl
482 << "#include \"base/dictionary.h\"" << std::endl
483 << "#include \"base/utility.h\"" << std::endl << std::endl
484 << "#ifdef _MSC_VER" << std::endl
485 << "#pragma warning( push )" << std::endl
486 << "#pragma warning( disable : 4244 )" << std::endl
487 << "#pragma warning( disable : 4800 )" << std::endl
488 << "#endif /* _MSC_VER */" << std::endl << std::endl;
490 ClassCompiler ctx(path, stream);
493 std::cout << "#ifdef _MSC_VER" << std::endl
494 << "#pragma warning ( pop )" << std::endl
495 << "#endif /* _MSC_VER */" << std::endl;