]> granicus.if.org Git - icinga2/blob - tools/mkclass/classcompiler.cpp
Merge branch 'feature/dtype-5036' into next
[icinga2] / tools / mkclass / classcompiler.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2013 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
25 using namespace icinga;
26
27 ClassCompiler::ClassCompiler(const std::string& path, std::istream *input)
28         : m_Path(path), m_Input(input)
29 {
30         InitializeScanner();
31 }
32
33 ClassCompiler::~ClassCompiler(void)
34 {
35         DestroyScanner();
36 }
37
38 std::string ClassCompiler::GetPath(void) const
39 {
40         return m_Path;
41 }
42
43 void *ClassCompiler::GetScanner(void)
44 {
45         return m_Scanner;
46 }
47
48 size_t ClassCompiler::ReadInput(char *buffer, size_t max_size)
49 {
50         m_Input->read(buffer, max_size);
51         return static_cast<size_t>(m_Input->gcount());
52 }
53
54 void ClassCompiler::HandleInclude(const std::string& path, const ClassDebugInfo& locp)
55 {
56         std::cout << "#include \"" << path << "\"" << std::endl << std::endl;
57 }
58
59 void ClassCompiler::HandleAngleInclude(const std::string& path, const ClassDebugInfo& locp)
60 {
61         std::cout << "#include <" << path << ">" << std::endl << std::endl;
62 }
63
64 void ClassCompiler::HandleNamespaceBegin(const std::string& name, const ClassDebugInfo& locp)
65 {
66         std::cout << "namespace " << name << std::endl
67                           << "{" << std::endl << std::endl;
68 }
69
70 void ClassCompiler::HandleNamespaceEnd(const ClassDebugInfo& locp)
71 {
72         std::cout << "}" << std::endl;
73 }
74
75 void ClassCompiler::HandleCode(const std::string& code, const ClassDebugInfo& locp)
76 {
77         std::cout << code << std::endl;
78 }
79
80 void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo& locp)
81 {
82         std::vector<Field>::const_iterator it;
83
84         /* forward declaration */
85         if (klass.Name.find_first_of(':') == std::string::npos)
86                 std::cout << "class " << klass.Name << ";" << std::endl << std::endl;
87
88         /* TypeImpl */
89         std::cout << "template<>" << std::endl
90                 << "class TypeImpl<" << klass.Name << ">"
91                 << " : public Type" << std::endl
92                 << "{" << std::endl
93                 << "public:" << std::endl;
94
95         /* GetName */
96         std::cout << "\t" << "virtual String GetName(void) const" << std::endl
97                   << "\t" << "{" << std::endl
98                   << "\t\t" << "return \"" << klass.Name << "\";" << std::endl
99                   << "\t" << "}" << std::endl << std::endl;
100
101         /* IsAbstract */
102         std::cout << "\t" << "virtual bool IsAbstract(void) const" << std::endl
103                   << "\t" << "{" << std::endl
104                   << "\t\t" << "return " << (klass.Abstract ? "true" : "false") << ";" << std::endl
105                   << "\t" << "}" << std::endl << std::endl;
106
107         /* GetBaseType */
108         std::cout << "\t" << "virtual const Type *GetBaseType(void) const" << std::endl
109                 << "\t" << "{" << std::endl;
110
111         std::cout << "\t\t" << "return ";
112
113         if (!klass.Parent.empty())
114                 std::cout << "Type::GetByName(\"" << klass.Parent << "\")";
115         else
116                 std::cout << "NULL";
117
118         std::cout << ";" << std::endl
119                           << "\t" << "}" << std::endl << std::endl;
120
121         /* GetFieldId */
122         std::cout << "\t" << "virtual int GetFieldId(const String& name) const" << std::endl
123                 << "\t" << "{" << std::endl
124                 << "\t\t" << "return StaticGetFieldId(name);" << std::endl
125                 << "\t" << "}" << std::endl << std::endl;
126
127         /* StaticGetFieldId */
128         std::cout << "\t" << "static int StaticGetFieldId(const String& name)" << std::endl
129                 << "\t" << "{" << std::endl
130                 << "\t\t" << "int offset = ";
131
132         if (!klass.Parent.empty())
133                 std::cout << "TypeImpl<" << klass.Parent << ">::StaticGetFieldCount()";
134         else
135                 std::cout << "0";
136
137         std::cout << ";" << std::endl << std::endl;
138
139         int num = 0;
140         for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
141                 std::cout << "\t\t" << "if (name == \"" << it->Name << "\")" << std::endl
142                         << "\t\t\t" << "return offset + " << num << ";" << std::endl;
143                 num++;
144         }
145
146         std::cout << std::endl
147                 << "\t\t" << "return ";
148
149         if (!klass.Parent.empty())
150                 std::cout << "TypeImpl<" << klass.Parent << ">::StaticGetFieldId(name)";
151         else
152                 std::cout << "-1";
153
154         std::cout << ";" << std::endl
155                 << "\t" << "}" << std::endl << std::endl;
156
157         /* GetFieldInfo */
158         std::cout << "\t" << "virtual Field GetFieldInfo(int id) const" << std::endl
159                 << "\t" << "{" << std::endl
160                 << "\t\t" << "return StaticGetFieldInfo(id);" << std::endl
161                 << "\t" << "}" << std::endl << std::endl;
162
163         /* StaticGetFieldInfo */
164         std::cout << "\t" << "static Field StaticGetFieldInfo(int id)" << std::endl
165                 << "\t" << "{" << std::endl;
166
167         if (!klass.Parent.empty())
168                 std::cout << "\t\t" << "int real_id = id - " << "TypeImpl<" << klass.Parent << ">::StaticGetFieldCount();" << std::endl
169                 << "\t\t" << "if (real_id < 0) { return " << "TypeImpl<" << klass.Parent << ">::StaticGetFieldInfo(id); }" << std::endl;
170
171         if (klass.Fields.size() > 0) {
172                 std::cout << "\t\t" << "switch (";
173
174                 if (!klass.Parent.empty())
175                         std::cout << "real_id";
176                 else
177                         std::cout << "id";
178
179                 std::cout << ") {" << std::endl;
180
181                 num = 0;
182                 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
183                         std::cout << "\t\t\t" << "case " << num << ":" << std::endl
184                                 << "\t\t\t\t" << "return Field(" << num << ", \"" << it->Name << "\", " << it->Attributes << ");" << std::endl;
185                         num++;
186                 }
187
188                 std::cout << "\t\t\t" << "default:" << std::endl
189                                   << "\t\t";
190         }
191
192         std::cout << "\t\t" << "throw std::runtime_error(\"Invalid field ID.\");" << std::endl;
193
194         if (klass.Fields.size() > 0)
195                 std::cout << "\t\t" << "}" << std::endl;
196
197         std::cout << "\t" << "}" << std::endl << std::endl;
198
199         /* GetFieldCount */
200         std::cout << "\t" << "virtual int GetFieldCount(void) const" << std::endl
201                 << "\t" << "{" << std::endl
202                 << "\t\t" << "return StaticGetFieldCount();" << std::endl
203                 << "\t" << "}" << std::endl << std::endl;
204
205         /* StaticGetFieldCount */
206         std::cout << "\t" << "static int StaticGetFieldCount(void)" << std::endl
207                 << "\t" << "{" << std::endl
208                 << "\t\t" << "return " << klass.Fields.size();
209
210         if (!klass.Parent.empty())
211                 std::cout << " + " << "TypeImpl<" << klass.Parent << ">::StaticGetFieldCount()";
212
213         std::cout << ";" << std::endl
214                 << "\t" << "}" << std::endl << std::endl;
215
216         std::cout << "};" << std::endl << std::endl;
217
218         /* ObjectImpl */
219         std::cout << "template<>" << std::endl
220                   << "class ObjectImpl<" << klass.Name << ">"
221                   << " : public " << (klass.Parent.empty() ? "Object" : klass.Parent) << std::endl
222                   << "{" << std::endl
223                   << "public:" << std::endl
224                   << "\t" << "DECLARE_PTR_TYPEDEFS(ObjectImpl<" << klass.Name << ">);" << std::endl << std::endl;
225
226         /* GetReflectionType */
227         std::cout << "\t" << "virtual const Type *GetReflectionType(void) const" << std::endl
228                           << "\t" << "{" << std::endl
229                           << "\t\t" << "return Type::GetByName(\"" << klass.Name << "\");" << std::endl
230                           << "\t" << "}" << std::endl << std::endl;
231
232         if (!klass.Fields.empty()) {
233                 /* constructor */
234                 std::cout << "public:" << std::endl
235                           << "\t" << "ObjectImpl<" << klass.Name << ">(void)" << std::endl
236                           << "\t" << "{" << std::endl;
237
238                 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
239                         std::cout << "\t\t" << "Set" << it->GetFriendlyName() << "(" << "GetDefault" << it->GetFriendlyName() << "());" << std::endl;
240                 }
241
242                 std::cout << "\t" << "}" << std::endl << std::endl;
243
244                 /* SetField */
245                 std::cout << "protected:" << std::endl
246                                   << "\t" << "virtual void SetField(int id, const Value& value)" << std::endl
247                                   << "\t" << "{" << std::endl;
248
249                 if (!klass.Parent.empty())
250                         std::cout << "\t\t" << "int real_id = id - TypeImpl<" << klass.Parent << ">::StaticGetFieldCount(); " << std::endl
251                                   << "\t\t" << "if (real_id < 0) { " << klass.Parent << "::SetField(id, value); return; }" << std::endl;
252
253                 std::cout << "\t\t" << "switch (";
254
255                 if (!klass.Parent.empty())
256                         std::cout << "real_id";
257                 else
258                         std::cout << "id";
259
260                 std::cout << ") {" << std::endl;
261
262                 num = 0;
263                 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
264                         std::cout << "\t\t\t" << "case " << num << ":" << std::endl
265                                           << "\t\t\t\t" << "Set" << it->GetFriendlyName() << "(";
266                         
267                         if (it->Attributes & FAEnum)
268                                 std::cout << "static_cast<" << it->Type << ">(static_cast<int>(";
269
270                         std::cout << "value";
271                         
272                         if (it->Attributes & FAEnum)
273                                 std::cout << "))";
274                         
275                         std::cout << ");" << std::endl
276                                           << "\t\t\t\t" << "break;" << std::endl;
277                         num++;
278                 }
279
280                 std::cout << "\t\t\t" << "default:" << std::endl
281                                   << "\t\t\t\t" << "throw std::runtime_error(\"Invalid field ID.\");" << std::endl
282                                   << "\t\t" << "}" << std::endl;
283
284                 std::cout << "\t" << "}" << std::endl << std::endl;
285
286                 /* GetField */
287                 std::cout << "protected:" << std::endl
288                                   << "\t" << "virtual Value GetField(int id) const" << std::endl
289                                   << "\t" << "{" << std::endl;
290
291                 if (!klass.Parent.empty())
292                         std::cout << "\t\t" << "int real_id = id - TypeImpl<" << klass.Parent << ">::StaticGetFieldCount(); " << std::endl
293                                           << "\t\t" << "if (real_id < 0) { return " << klass.Parent << "::GetField(id); }" << std::endl;
294
295                 std::cout << "\t\t" << "switch (";
296
297                 if (!klass.Parent.empty())
298                         std::cout << "real_id";
299                 else
300                         std::cout << "id";
301
302                 std::cout << ") {" << std::endl;
303
304                 num = 0;
305                 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
306                         std::cout << "\t\t\t" << "case " << num << ":" << std::endl
307                                           << "\t\t\t\t" << "return Get" << it->GetFriendlyName() << "();" << std::endl;
308                         num++;
309                 }
310
311                 std::cout << "\t\t\t" << "default:" << std::endl
312                                   << "\t\t\t\t" << "throw std::runtime_error(\"Invalid field ID.\");" << std::endl
313                                   << "\t\t" << "}" << std::endl;
314
315                 std::cout << "\t" << "}" << std::endl << std::endl;
316
317                 /* getters */
318                 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
319                         std::string prot;
320
321                         if (it->Attributes & FAGetProtected)
322                                 prot = "protected";
323                         else
324                                 prot = "public";
325
326                         std::cout << prot << ":" << std::endl
327                                           << "\t" << it->Type << " Get" << it->GetFriendlyName() << "(void) const" << std::endl
328                                           << "\t" << "{" << std::endl;
329
330                         if (it->GetAccessor.empty())
331                                 std::cout << "\t\t" << "return m_" << it->GetFriendlyName() << ";" << std::endl;
332                         else
333                                 std::cout << it->GetAccessor << std::endl;
334
335                         std::cout << "\t" << "}" << std::endl << std::endl;
336                 }
337
338                 /* setters */
339                 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
340                         std::string prot;
341
342                         if (it->Attributes & FASetProtected)
343                                 prot = "protected";
344                         else if (it->Attributes & FAConfig)
345                                 prot = "private";
346                         else
347                                 prot = "public";
348
349                         std::cout << prot << ":" << std::endl
350                                           << "\t" << "void Set" << it->GetFriendlyName() << "(const " << it->Type << "& value)" << std::endl
351                                           << "\t" << "{" << std::endl;
352
353                         if (it->SetAccessor.empty())
354                                 std::cout << "\t\t" << "m_" << it->GetFriendlyName() << " = value;" << std::endl;
355                         else
356                                 std::cout << it->SetAccessor << std::endl;
357
358                         std::cout << "\t" << "}" << std::endl << std::endl;
359                 }
360
361                 /* default */
362                 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
363                         std::string prot;
364
365                         std::cout << "private:" << std::endl
366                                           << "\t" << it->Type << " GetDefault" << it->GetFriendlyName() << "(void) const" << std::endl
367                                           << "\t" << "{" << std::endl;
368
369                         if (it->DefaultAccessor.empty())
370                                 std::cout << "\t\t" << "return " << it->Type << "();" << std::endl;
371                         else
372                                 std::cout << it->DefaultAccessor << std::endl;
373
374                         std::cout << "\t" << "}" << std::endl;
375                 }
376
377                 /* instance variables */
378                 std::cout << "private:" << std::endl;
379
380                 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
381                         std::cout << "\t" << it->Type << " m_" << it->GetFriendlyName() << ";" << std::endl;
382                 }
383         }
384
385         std::cout << "};" << std::endl << std::endl;
386
387         /* FactoryHelper */
388         if (klass.Abstract) {
389                 std::cout << "template<>" << std::endl
390                           << "struct FactoryHelper<" << klass.Name << ">" << std::endl
391                           << "{" << std::endl
392                           << "\t" << "Type::Factory GetFactory(void)" << std::endl
393                           << "\t" << "{" << std::endl
394                           << "\t\t" << "return Type::Factory();"
395                           << "\t" << "}"
396                           << "};" << std::endl << std::endl;
397         }
398 }
399
400 void ClassCompiler::CompileFile(const std::string& path)
401 {
402         std::ifstream stream;
403         stream.open(path.c_str(), std::ifstream::in);
404
405         if (!stream)
406                 throw std::invalid_argument("Could not open config file: " + path);
407
408         return CompileStream(path, &stream);
409 }
410
411 void ClassCompiler::CompileStream(const std::string& path, std::istream *stream)
412 {
413         stream->exceptions(std::istream::badbit);
414
415         std::cout << "#include \"base/object.h\"" << std::endl
416                           << "#include \"base/type.h\"" << std::endl
417                           << "#include \"base/debug.h\"" << std::endl
418                           << "#include \"base/value.h\"" << std::endl
419                           << "#include \"base/array.h\"" << std::endl
420                           << "#include \"base/dictionary.h\"" << std::endl << std::endl
421                           << "#ifdef _MSC_VER" << std::endl
422                           << "#pragma warning( push )" << std::endl
423                           << "#pragma warning( disable : 4244 )" << std::endl
424                           << "#pragma warning( disable : 4800 )" << std::endl
425                           << "#endif /* _MSC_VER */" << std::endl << std::endl;
426
427         ClassCompiler ctx(path, stream);
428         ctx.Compile();
429
430         std::cout << "#ifdef _MSC_VER" << std::endl
431                           << "#pragma warning ( pop )" << std::endl
432                           << "#endif /* _MSC_VER */" << std::endl;
433 }