]> granicus.if.org Git - icinga2/blob - tools/mkclass/classcompiler.cpp
Implement the ReflectionType class.
[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         /* ReflectionTypeImpl */
89         std::cout << "template<>" << std::endl
90                 << "class ReflectionTypeImpl<" << klass.Name << ">"
91                 << " : public ReflectionType, public Singleton<ReflectionTypeImpl<" << klass.Name << "> >" << std::endl
92                 << "{" << std::endl
93                 << "public:" << std::endl;
94
95         /* GetFieldId */
96         std::cout << "\t" << "virtual int GetFieldId(const String& name) const" << std::endl
97                 << "\t" << "{" << std::endl
98                 << "\t\t" << "return StaticGetFieldId(name);" << std::endl
99                 << "\t" << "}" << std::endl << std::endl;
100
101         /* StaticGetFieldId */
102         std::cout << "\t" << "static int StaticGetFieldId(const String& name)" << std::endl
103                 << "\t" << "{" << std::endl
104                 << "\t\t" << "int offset = ";
105
106         if (!klass.Parent.empty())
107                 std::cout << "ReflectionTypeImpl<" << klass.Parent << ">::StaticGetFieldCount()";
108         else
109                 std::cout << "0";
110
111         std::cout << ";" << std::endl << std::endl;
112
113         int num = 0;
114         for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
115                 std::cout << "\t\t" << "if (name == \"" << it->Name << "\")" << std::endl
116                         << "\t\t\t" << "return offset + " << num << ";" << std::endl;
117                 num++;
118         }
119
120         std::cout << std::endl
121                 << "\t\t" << "return ";
122
123         if (!klass.Parent.empty())
124                 std::cout << "ReflectionTypeImpl<" << klass.Parent << ">::StaticGetFieldId(name)";
125         else
126                 std::cout << "-1";
127
128         std::cout << ";" << std::endl
129                 << "\t" << "}" << std::endl << std::endl;
130
131         /* GetFieldInfo */
132         std::cout << "\t" << "virtual ReflectionField GetFieldInfo(int id) const" << std::endl
133                 << "\t" << "{" << std::endl
134                 << "\t\t" << "return StaticGetFieldInfo(id);" << std::endl
135                 << "\t" << "}" << std::endl << std::endl;
136
137         /* StaticGetFieldInfo */
138         std::cout << "\t" << "static ReflectionField StaticGetFieldInfo(int id)" << std::endl
139                 << "\t" << "{" << std::endl;
140
141         if (!klass.Parent.empty())
142                 std::cout << "\t\t" << "int real_id = id - " << "ReflectionTypeImpl<" << klass.Parent << ">::StaticGetFieldCount();" << std::endl
143                 << "\t\t" << "if (real_id < 0) { return " << "ReflectionTypeImpl<" << klass.Parent << ">::StaticGetFieldInfo(id); }" << std::endl;
144
145         std::cout << "\t\t" << "switch (";
146
147         if (!klass.Parent.empty())
148                 std::cout << "real_id";
149         else
150                 std::cout << "id";
151
152         std::cout << ") {" << std::endl;
153
154         num = 0;
155         for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
156                 std::cout << "\t\t\t" << "case " << num << ":" << std::endl
157                         << "\t\t\t\t" << "return ReflectionField(" << num << ", \"" << it->Name << "\", " << it->Attributes << ");" << std::endl;
158                 num++;
159         }
160
161         std::cout << "\t\t\t" << "default:" << std::endl
162                 << "\t\t\t\t" << "throw std::runtime_error(\"Invalid field ID.\");" << std::endl
163                 << "\t\t" << "}" << std::endl;
164
165         std::cout << "\t" << "}" << std::endl << std::endl;
166
167         /* GetFieldCount */
168         std::cout << "\t" << "virtual int GetFieldCount(void) const" << std::endl
169                 << "\t" << "{" << std::endl
170                 << "\t\t" << "return StaticGetFieldCount();" << std::endl
171                 << "\t" << "}" << std::endl << std::endl;
172
173         /* StaticGetFieldCount */
174         std::cout << "\t" << "static int StaticGetFieldCount(void)" << std::endl
175                 << "\t" << "{" << std::endl
176                 << "\t\t" << "return " << klass.Fields.size();
177
178         if (!klass.Parent.empty())
179                 std::cout << " + " << "ReflectionTypeImpl<" << klass.Parent << ">::StaticGetFieldCount()";
180
181         std::cout << ";" << std::endl
182                 << "\t" << "}" << std::endl << std::endl;
183
184         std::cout << "};" << std::endl << std::endl;
185
186         /* ReflectionObjectImpl */
187         std::cout << "template<>" << std::endl
188                   << "class ReflectionObjectImpl<" << klass.Name << ">"
189                   << " : public " << (klass.Parent.empty() ? "ReflectionObject" : klass.Parent) << std::endl
190                   << "{" << std::endl
191                   << "public:" << std::endl
192                   << "\t" << "DECLARE_PTR_TYPEDEFS(ReflectionObjectImpl<" << klass.Name << ">);" << std::endl << std::endl;
193
194         /* GetType */
195         std::cout << "\t" << "virtual const ReflectionType *GetReflectionType(void) const" << std::endl
196                           << "\t" << "{" << std::endl
197                           << "\t\t" << "return ReflectionTypeImpl<" << klass.Name << ">::GetInstance();" << std::endl
198                           << "\t" << "}" << std::endl << std::endl;
199
200         if (!klass.Fields.empty()) {
201                 /* constructor */
202                 std::cout << "public:" << std::endl
203                           << "\t" << "ReflectionObjectImpl<" << klass.Name << ">(void)" << std::endl
204                           << "\t" << "{" << std::endl;
205
206                 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
207                         std::cout << "\t\t" << "Set" << it->GetFriendlyName() << "(" << "GetDefault" << it->GetFriendlyName() << "());" << std::endl;
208                 }
209
210                 std::cout << "\t" << "}" << std::endl << std::endl;
211
212                 /* SetField */
213                 std::cout << "protected:" << std::endl
214                                   << "\t" << "virtual void SetField(int id, const Value& value)" << std::endl
215                                   << "\t" << "{" << std::endl;
216
217                 if (!klass.Parent.empty())
218                         std::cout << "\t\t" << "int real_id = id - ReflectionTypeImpl<" << klass.Parent << ">::StaticGetFieldCount(); " << std::endl
219                                   << "\t\t" << "if (real_id < 0) { " << klass.Parent << "::SetField(id, value); return; }" << std::endl;
220
221                 std::cout << "\t\t" << "switch (";
222
223                 if (!klass.Parent.empty())
224                         std::cout << "real_id";
225                 else
226                         std::cout << "id";
227
228                 std::cout << ") {" << std::endl;
229
230                 num = 0;
231                 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
232                         std::cout << "\t\t\t" << "case " << num << ":" << std::endl
233                                           << "\t\t\t\t" << "Set" << it->GetFriendlyName() << "(";
234                         
235                         if (it->Attributes & FAEnum)
236                                 std::cout << "static_cast<" << it->Type << ">(static_cast<int>(";
237
238                         std::cout << "value";
239                         
240                         if (it->Attributes & FAEnum)
241                                 std::cout << "))";
242                         
243                         std::cout << ");" << std::endl
244                                           << "\t\t\t\t" << "break;" << std::endl;
245                         num++;
246                 }
247
248                 std::cout << "\t\t\t" << "default:" << std::endl
249                                   << "\t\t\t\t" << "throw std::runtime_error(\"Invalid field ID.\");" << std::endl
250                                   << "\t\t" << "}" << std::endl;
251
252                 std::cout << "\t" << "}" << std::endl << std::endl;
253
254                 /* GetField */
255                 std::cout << "protected:" << std::endl
256                                   << "\t" << "virtual Value GetField(int id) const" << std::endl
257                                   << "\t" << "{" << std::endl;
258
259                 if (!klass.Parent.empty())
260                         std::cout << "\t\t" << "int real_id = id - ReflectionTypeImpl<" << klass.Parent << ">::StaticGetFieldCount(); " << std::endl
261                                           << "\t\t" << "if (real_id < 0) { return " << klass.Parent << "::GetField(id); }" << std::endl;
262
263                 std::cout << "\t\t" << "switch (";
264
265                 if (!klass.Parent.empty())
266                         std::cout << "real_id";
267                 else
268                         std::cout << "id";
269
270                 std::cout << ") {" << std::endl;
271
272                 num = 0;
273                 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
274                         std::cout << "\t\t\t" << "case " << num << ":" << std::endl
275                                           << "\t\t\t\t" << "return Get" << it->GetFriendlyName() << "();" << std::endl;
276                         num++;
277                 }
278
279                 std::cout << "\t\t\t" << "default:" << std::endl
280                                   << "\t\t\t\t" << "throw std::runtime_error(\"Invalid field ID.\");" << std::endl
281                                   << "\t\t" << "}" << std::endl;
282
283                 std::cout << "\t" << "}" << std::endl << std::endl;
284
285                 /* getters */
286                 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
287                         std::string prot;
288
289                         if (it->Attributes & FAGetProtected)
290                                 prot = "protected";
291                         else
292                                 prot = "public";
293
294                         std::cout << prot << ":" << std::endl
295                                           << "\t" << it->Type << " Get" << it->GetFriendlyName() << "(void) const" << std::endl
296                                           << "\t" << "{" << std::endl;
297
298                         if (it->GetAccessor.empty())
299                                 std::cout << "\t\t" << "return m_" << it->GetFriendlyName() << ";" << std::endl;
300                         else
301                                 std::cout << it->GetAccessor << std::endl;
302
303                         std::cout << "\t" << "}" << std::endl << std::endl;
304                 }
305
306                 /* setters */
307                 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
308                         std::string prot;
309
310                         if (it->Attributes & FASetProtected)
311                                 prot = "protected";
312                         else if (it->Attributes & FAConfig)
313                                 prot = "private";
314                         else
315                                 prot = "public";
316
317                         std::cout << prot << ":" << std::endl
318                                           << "\t" << "void Set" << it->GetFriendlyName() << "(const " << it->Type << "& value)" << std::endl
319                                           << "\t" << "{" << std::endl;
320
321                         if (it->SetAccessor.empty())
322                                 std::cout << "\t\t" << "m_" << it->GetFriendlyName() << " = value;" << std::endl;
323                         else
324                                 std::cout << it->SetAccessor << std::endl;
325
326                         std::cout << "\t" << "}" << std::endl << std::endl;
327                 }
328
329                 /* default */
330                 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
331                         std::string prot;
332
333                         std::cout << "private:" << std::endl
334                                           << "\t" << it->Type << " GetDefault" << it->GetFriendlyName() << "(void) const" << std::endl
335                                           << "\t" << "{" << std::endl;
336
337                         if (it->DefaultAccessor.empty())
338                                 std::cout << "\t\t" << "return Empty;" << std::endl;
339                         else
340                                 std::cout << it->DefaultAccessor << std::endl;
341
342                         std::cout << "\t" << "}" << std::endl;
343                 }
344
345                 /* instance variables */
346                 std::cout << "private:" << std::endl;
347
348                 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
349                         std::cout << "\t" << it->Type << " m_" << it->GetFriendlyName() << ";" << std::endl;
350                 }
351         }
352
353         std::cout << "};" << std::endl << std::endl;
354 }
355
356 void ClassCompiler::CompileFile(const std::string& path)
357 {
358         std::ifstream stream;
359         stream.open(path.c_str(), std::ifstream::in);
360
361         if (!stream)
362                 throw std::invalid_argument("Could not open config file: " + path);
363
364         return CompileStream(path, &stream);
365 }
366
367 void ClassCompiler::CompileStream(const std::string& path, std::istream *stream)
368 {
369         stream->exceptions(std::istream::badbit);
370
371         std::cout << "#include \"base/reflectionobject.h\"" << std::endl
372                           << "#include \"base/singleton.h\"" << std::endl
373                           << "#include \"base/debug.h\"" << std::endl
374                           << "#include \"base/value.h\"" << std::endl
375                           << "#include \"base/array.h\"" << std::endl
376                           << "#include \"base/dictionary.h\"" << std::endl << std::endl
377                           << "#ifdef _MSC_VER" << std::endl
378                           << "#pragma warning( push )" << std::endl
379                           << "#pragma warning( disable : 4244 )" << std::endl
380                           << "#pragma warning( disable : 4800 )" << std::endl
381                           << "#endif /* _MSC_VER */" << std::endl << std::endl;
382
383         ClassCompiler ctx(path, stream);
384         ctx.Compile();
385
386         std::cout << "#ifdef _MSC_VER" << std::endl
387                           << "#pragma warning ( pop )" << std::endl
388                           << "#endif /* _MSC_VER */" << std::endl;
389 }