]> granicus.if.org Git - icinga2/blob - tools/mkclass/classcompiler.cpp
Implement missing operators for the Value class.
[icinga2] / tools / mkclass / classcompiler.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org)    *
4  *                                                                            *
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.                     *
9  *                                                                            *
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.                               *
14  *                                                                            *
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  ******************************************************************************/
19
20 #include "classcompiler.h"
21 #include <iostream>
22 #include <fstream>
23 #include <stdexcept>
24 #include <map>
25 #include <vector>
26
27 using namespace icinga;
28
29 ClassCompiler::ClassCompiler(const std::string& path, std::istream *input)
30         : m_Path(path), m_Input(input)
31 {
32         InitializeScanner();
33 }
34
35 ClassCompiler::~ClassCompiler(void)
36 {
37         DestroyScanner();
38 }
39
40 std::string ClassCompiler::GetPath(void) const
41 {
42         return m_Path;
43 }
44
45 void *ClassCompiler::GetScanner(void)
46 {
47         return m_Scanner;
48 }
49
50 size_t ClassCompiler::ReadInput(char *buffer, size_t max_size)
51 {
52         m_Input->read(buffer, max_size);
53         return static_cast<size_t>(m_Input->gcount());
54 }
55
56 void ClassCompiler::HandleInclude(const std::string& path, const ClassDebugInfo& locp)
57 {
58         std::cout << "#include \"" << path << "\"" << std::endl << std::endl;
59 }
60
61 void ClassCompiler::HandleAngleInclude(const std::string& path, const ClassDebugInfo& locp)
62 {
63         std::cout << "#include <" << path << ">" << std::endl << std::endl;
64 }
65
66 void ClassCompiler::HandleNamespaceBegin(const std::string& name, const ClassDebugInfo& locp)
67 {
68         std::cout << "namespace " << name << std::endl
69                           << "{" << std::endl << std::endl;
70 }
71
72 void ClassCompiler::HandleNamespaceEnd(const ClassDebugInfo& locp)
73 {
74         std::cout << "}" << std::endl;
75 }
76
77 void ClassCompiler::HandleCode(const std::string& code, const ClassDebugInfo& locp)
78 {
79         std::cout << code << std::endl;
80 }
81
82 unsigned long ClassCompiler::SDBM(const std::string& str, size_t len = std::string::npos)
83 {
84         unsigned long hash = 0;
85         size_t current = 0;
86
87         std::string::const_iterator it;
88
89         for (it = str.begin(); it != str.end(); it++) {
90                 if (current >= len)
91                         break;
92
93                 char c = *it;
94
95                 hash = c + (hash << 6) + (hash << 16) - hash;
96
97                 current++;
98         }
99
100         return hash;
101 }
102
103 void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo& locp)
104 {
105         std::vector<Field>::const_iterator it;
106
107         /* forward declaration */
108         if (klass.Name.find_first_of(':') == std::string::npos)
109                 std::cout << "class " << klass.Name << ";" << std::endl << std::endl;
110
111         /* TypeImpl */
112         std::cout << "template<>" << std::endl
113                 << "class TypeImpl<" << klass.Name << ">"
114                 << " : public Type" << std::endl
115                 << "{" << std::endl
116                 << "public:" << std::endl;
117
118         /* GetName */
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;
123
124         /* GetAttributes */
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;
129
130         /* GetBaseType */
131         std::cout << "\t" << "virtual const Type *GetBaseType(void) const" << std::endl
132                 << "\t" << "{" << std::endl;
133
134         std::cout << "\t\t" << "return ";
135
136         if (!klass.Parent.empty())
137                 std::cout << "Type::GetByName(\"" << klass.Parent << "\")";
138         else
139                 std::cout << "NULL";
140
141         std::cout << ";" << std::endl
142                           << "\t" << "}" << std::endl << std::endl;
143
144         /* GetFieldId */
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;
149
150         /* StaticGetFieldId */
151         std::cout << "\t" << "static int StaticGetFieldId(const String& name)" << std::endl
152                 << "\t" << "{" << std::endl;
153
154         if (!klass.Fields.empty()) {
155                 std::cout << "\t\t" << "int offset = ";
156
157                 if (!klass.Parent.empty())
158                         std::cout << "TypeImpl<" << klass.Parent << ">::StaticGetFieldCount()";
159                 else
160                         std::cout << "0";
161
162                 std::cout << ";" << std::endl << std::endl;
163         }
164
165         std::map<int, std::vector<std::pair<int, std::string> > > jumptable;
166
167         int hlen = 0, collisions = 0;
168
169         do {
170                 int num = 0;
171
172                 hlen++;
173                 jumptable.clear();
174                 collisions = 0;
175
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));
179                         num++;
180
181                         if (jumptable[hash].size() > 1)
182                                 collisions++;
183                 }
184         } while (collisions >= 5 && hlen < 8);
185
186         if (!klass.Fields.empty()) {
187                 std::cout << "\t\tswitch (static_cast<int>(Utility::SDBM(name, " << hlen << "))) {" << std::endl;
188
189                 std::map<int, std::vector<std::pair<int, std::string> > >::const_iterator itj;
190
191                 for (itj = jumptable.begin(); itj != jumptable.end(); itj++) {
192                         std::cout << "\t\t\tcase " << itj->first << ":" << std::endl;
193
194                         std::vector<std::pair<int, std::string> >::const_iterator itf;
195
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;
199                         }
200
201                         std::cout << std::endl
202                                   << "\t\t\t\tbreak;" << std::endl;
203                 }
204
205                 std::cout << "\t\t}" << std::endl;
206         }
207
208         std::cout << std::endl
209                 << "\t\t" << "return ";
210
211         if (!klass.Parent.empty())
212                 std::cout << "TypeImpl<" << klass.Parent << ">::StaticGetFieldId(name)";
213         else
214                 std::cout << "-1";
215
216         std::cout << ";" << std::endl
217                 << "\t" << "}" << std::endl << std::endl;
218
219         /* GetFieldInfo */
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;
224
225         /* StaticGetFieldInfo */
226         std::cout << "\t" << "static Field StaticGetFieldInfo(int id)" << std::endl
227                 << "\t" << "{" << std::endl;
228
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;
232
233         if (klass.Fields.size() > 0) {
234                 std::cout << "\t\t" << "switch (";
235
236                 if (!klass.Parent.empty())
237                         std::cout << "real_id";
238                 else
239                         std::cout << "id";
240
241                 std::cout << ") {" << std::endl;
242
243                 size_t num = 0;
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;
247                         num++;
248                 }
249
250                 std::cout << "\t\t\t" << "default:" << std::endl
251                                   << "\t\t";
252         }
253
254         std::cout << "\t\t" << "throw std::runtime_error(\"Invalid field ID.\");" << std::endl;
255
256         if (klass.Fields.size() > 0)
257                 std::cout << "\t\t" << "}" << std::endl;
258
259         std::cout << "\t" << "}" << std::endl << std::endl;
260
261         /* GetFieldCount */
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;
266
267         /* StaticGetFieldCount */
268         std::cout << "\t" << "static int StaticGetFieldCount(void)" << std::endl
269                 << "\t" << "{" << std::endl
270                 << "\t\t" << "return " << klass.Fields.size();
271
272         if (!klass.Parent.empty())
273                 std::cout << " + " << "TypeImpl<" << klass.Parent << ">::StaticGetFieldCount()";
274
275         std::cout << ";" << std::endl
276                 << "\t" << "}" << std::endl << std::endl;
277
278         std::cout << "};" << std::endl << std::endl;
279
280         /* ObjectImpl */
281         std::cout << "template<>" << std::endl
282                   << "class ObjectImpl<" << klass.Name << ">"
283                   << " : public " << (klass.Parent.empty() ? "Object" : klass.Parent) << std::endl
284                   << "{" << std::endl
285                   << "public:" << std::endl
286                   << "\t" << "DECLARE_PTR_TYPEDEFS(ObjectImpl<" << klass.Name << ">);" << std::endl << std::endl;
287
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;
293
294         if (!klass.Fields.empty()) {
295                 /* constructor */
296                 std::cout << "public:" << std::endl
297                           << "\t" << "ObjectImpl<" << klass.Name << ">(void)" << std::endl
298                           << "\t" << "{" << std::endl;
299
300                 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
301                         std::cout << "\t\t" << "Set" << it->GetFriendlyName() << "(" << "GetDefault" << it->GetFriendlyName() << "());" << std::endl;
302                 }
303
304                 std::cout << "\t" << "}" << std::endl << std::endl;
305
306                 /* SetField */
307                 std::cout << "protected:" << std::endl
308                                   << "\t" << "virtual void SetField(int id, const Value& value)" << std::endl
309                                   << "\t" << "{" << std::endl;
310
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;
314
315                 std::cout << "\t\t" << "switch (";
316
317                 if (!klass.Parent.empty())
318                         std::cout << "real_id";
319                 else
320                         std::cout << "id";
321
322                 std::cout << ") {" << std::endl;
323
324                 size_t num = 0;
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() << "(";
328                         
329                         if (it->Attributes & FAEnum)
330                                 std::cout << "static_cast<" << it->Type << ">(static_cast<int>(";
331
332                         std::cout << "value";
333                         
334                         if (it->Attributes & FAEnum)
335                                 std::cout << "))";
336                         
337                         std::cout << ");" << std::endl
338                                           << "\t\t\t\t" << "break;" << std::endl;
339                         num++;
340                 }
341
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;
345
346                 std::cout << "\t" << "}" << std::endl << std::endl;
347
348                 /* GetField */
349                 std::cout << "protected:" << std::endl
350                                   << "\t" << "virtual Value GetField(int id) const" << std::endl
351                                   << "\t" << "{" << std::endl;
352
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;
356
357                 std::cout << "\t\t" << "switch (";
358
359                 if (!klass.Parent.empty())
360                         std::cout << "real_id";
361                 else
362                         std::cout << "id";
363
364                 std::cout << ") {" << std::endl;
365
366                 num = 0;
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;
370                         num++;
371                 }
372
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;
376
377                 std::cout << "\t" << "}" << std::endl << std::endl;
378
379                 /* getters */
380                 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
381                         std::string prot;
382
383                         if (it->Attributes & FAGetProtected)
384                                 prot = "protected";
385                         else
386                                 prot = "public";
387
388                         std::cout << prot << ":" << std::endl
389                                           << "\t" << it->Type << " Get" << it->GetFriendlyName() << "(void) const" << std::endl
390                                           << "\t" << "{" << std::endl;
391
392                         if (it->GetAccessor.empty())
393                                 std::cout << "\t\t" << "return m_" << it->GetFriendlyName() << ";" << std::endl;
394                         else
395                                 std::cout << it->GetAccessor << std::endl;
396
397                         std::cout << "\t" << "}" << std::endl << std::endl;
398                 }
399
400                 /* setters */
401                 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
402                         std::string prot;
403
404                         if (it->Attributes & FASetProtected)
405                                 prot = "protected";
406                         else if (it->Attributes & FAConfig)
407                                 prot = "private";
408                         else
409                                 prot = "public";
410
411                         std::cout << prot << ":" << std::endl
412                                           << "\t" << "void Set" << it->GetFriendlyName() << "(";
413
414                         if (it->Type == "bool" || it->Type == "double" || it->Type == "int")
415                                 std::cout << it->Type;
416                         else
417                                 std::cout << "const " << it->Type << "&";
418
419                         std::cout << " value)" << std::endl
420                                           << "\t" << "{" << std::endl;
421
422                         if (it->SetAccessor.empty())
423                                 std::cout << "\t\t" << "m_" << it->GetFriendlyName() << " = value;" << std::endl;
424                         else
425                                 std::cout << it->SetAccessor << std::endl;
426
427                         std::cout << "\t" << "}" << std::endl << std::endl;
428                 }
429
430                 /* default */
431                 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
432                         std::string prot;
433
434                         std::cout << "private:" << std::endl
435                                           << "\t" << it->Type << " GetDefault" << it->GetFriendlyName() << "(void) const" << std::endl
436                                           << "\t" << "{" << std::endl;
437
438                         if (it->DefaultAccessor.empty())
439                                 std::cout << "\t\t" << "return " << it->Type << "();" << std::endl;
440                         else
441                                 std::cout << it->DefaultAccessor << std::endl;
442
443                         std::cout << "\t" << "}" << std::endl;
444                 }
445
446                 /* instance variables */
447                 std::cout << "private:" << std::endl;
448
449                 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
450                         std::cout << "\t" << it->Type << " m_" << it->GetFriendlyName() << ";" << std::endl;
451                 }
452         }
453
454         std::cout << "};" << std::endl << std::endl;
455
456         /* FactoryHelper */
457         if (klass.Attributes & TAAbstract) {
458                 std::cout << "template<>" << std::endl
459                           << "struct FactoryHelper<" << klass.Name << ">" << std::endl
460                           << "{" << std::endl
461                           << "\t" << "Type::Factory GetFactory(void)" << std::endl
462                           << "\t" << "{" << std::endl
463                           << "\t\t" << "return Type::Factory();"
464                           << "\t" << "}"
465                           << "};" << std::endl << std::endl;
466         }
467 }
468
469 void ClassCompiler::CompileFile(const std::string& path)
470 {
471         std::ifstream stream;
472         stream.open(path.c_str(), std::ifstream::in);
473
474         if (!stream)
475                 throw std::invalid_argument("Could not open config file: " + path);
476
477         return CompileStream(path, &stream);
478 }
479
480 void ClassCompiler::CompileStream(const std::string& path, std::istream *stream)
481 {
482         stream->exceptions(std::istream::badbit);
483
484         std::cout << "#include \"base/object.h\"" << std::endl
485                           << "#include \"base/type.h\"" << std::endl
486                           << "#include \"base/debug.h\"" << std::endl
487                           << "#include \"base/value.h\"" << std::endl
488                           << "#include \"base/array.h\"" << std::endl
489                           << "#include \"base/dictionary.h\"" << std::endl
490                           << "#include \"base/utility.h\"" << std::endl << std::endl
491                           << "#ifdef _MSC_VER" << std::endl
492                           << "#pragma warning( push )" << std::endl
493                           << "#pragma warning( disable : 4244 )" << std::endl
494                           << "#pragma warning( disable : 4800 )" << std::endl
495                           << "#endif /* _MSC_VER */" << std::endl << std::endl;
496
497         ClassCompiler ctx(path, stream);
498         ctx.Compile();
499
500         std::cout << "#ifdef _MSC_VER" << std::endl
501                           << "#pragma warning ( pop )" << std::endl
502                           << "#endif /* _MSC_VER */" << std::endl;
503 }