1 /******************************************************************************
3 * Copyright (C) 2012-2013 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"
25 using namespace icinga;
27 ClassCompiler::ClassCompiler(const std::string& path, std::istream *input)
28 : m_Path(path), m_Input(input)
33 ClassCompiler::~ClassCompiler(void)
38 std::string ClassCompiler::GetPath(void) const
43 void *ClassCompiler::GetScanner(void)
48 size_t ClassCompiler::ReadInput(char *buffer, size_t max_size)
50 m_Input->read(buffer, max_size);
51 return static_cast<size_t>(m_Input->gcount());
54 void ClassCompiler::HandleInclude(const std::string& path, const ClassDebugInfo& locp)
56 std::cout << "#include \"" << path << "\"" << std::endl << std::endl;
59 void ClassCompiler::HandleAngleInclude(const std::string& path, const ClassDebugInfo& locp)
61 std::cout << "#include <" << path << ">" << std::endl << std::endl;
64 void ClassCompiler::HandleNamespaceBegin(const std::string& name, const ClassDebugInfo& locp)
66 std::cout << "namespace " << name << std::endl
67 << "{" << std::endl << std::endl;
70 void ClassCompiler::HandleNamespaceEnd(const ClassDebugInfo& locp)
72 std::cout << "}" << std::endl;
75 void ClassCompiler::HandleCode(const std::string& code, const ClassDebugInfo& locp)
77 std::cout << code << std::endl;
80 void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo& locp)
82 std::vector<Field>::const_iterator it;
84 /* forward declaration */
85 if (klass.Name.find_first_of(':') == std::string::npos)
86 std::cout << "class " << klass.Name << ";" << std::endl << std::endl;
89 std::cout << "template<>" << std::endl
90 << "class TypeImpl<" << klass.Name << ">"
91 << " : public Type" << std::endl
93 << "public:" << std::endl;
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;
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;
108 std::cout << "\t" << "virtual const Type *GetBaseType(void) const" << std::endl
109 << "\t" << "{" << std::endl;
111 std::cout << "\t\t" << "return ";
113 if (!klass.Parent.empty())
114 std::cout << "Type::GetByName(\"" << klass.Parent << "\")";
118 std::cout << ";" << std::endl
119 << "\t" << "}" << std::endl << std::endl;
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;
127 /* StaticGetFieldId */
128 std::cout << "\t" << "static int StaticGetFieldId(const String& name)" << std::endl
129 << "\t" << "{" << std::endl
130 << "\t\t" << "int offset = ";
132 if (!klass.Parent.empty())
133 std::cout << "TypeImpl<" << klass.Parent << ">::StaticGetFieldCount()";
137 std::cout << ";" << std::endl << std::endl;
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;
146 std::cout << std::endl
147 << "\t\t" << "return ";
149 if (!klass.Parent.empty())
150 std::cout << "TypeImpl<" << klass.Parent << ">::StaticGetFieldId(name)";
154 std::cout << ";" << std::endl
155 << "\t" << "}" << std::endl << std::endl;
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;
163 /* StaticGetFieldInfo */
164 std::cout << "\t" << "static Field StaticGetFieldInfo(int id)" << std::endl
165 << "\t" << "{" << std::endl;
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;
171 if (klass.Fields.size() > 0) {
172 std::cout << "\t\t" << "switch (";
174 if (!klass.Parent.empty())
175 std::cout << "real_id";
179 std::cout << ") {" << std::endl;
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;
188 std::cout << "\t\t\t" << "default:" << std::endl
192 std::cout << "\t\t" << "throw std::runtime_error(\"Invalid field ID.\");" << std::endl;
194 if (klass.Fields.size() > 0)
195 std::cout << "\t\t" << "}" << std::endl;
197 std::cout << "\t" << "}" << std::endl << std::endl;
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;
205 /* StaticGetFieldCount */
206 std::cout << "\t" << "static int StaticGetFieldCount(void)" << std::endl
207 << "\t" << "{" << std::endl
208 << "\t\t" << "return " << klass.Fields.size();
210 if (!klass.Parent.empty())
211 std::cout << " + " << "TypeImpl<" << klass.Parent << ">::StaticGetFieldCount()";
213 std::cout << ";" << std::endl
214 << "\t" << "}" << std::endl << std::endl;
216 std::cout << "};" << std::endl << std::endl;
219 std::cout << "template<>" << std::endl
220 << "class ObjectImpl<" << klass.Name << ">"
221 << " : public " << (klass.Parent.empty() ? "Object" : klass.Parent) << std::endl
223 << "public:" << std::endl
224 << "\t" << "DECLARE_PTR_TYPEDEFS(ObjectImpl<" << klass.Name << ">);" << std::endl << std::endl;
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;
232 if (!klass.Fields.empty()) {
234 std::cout << "public:" << std::endl
235 << "\t" << "ObjectImpl<" << klass.Name << ">(void)" << std::endl
236 << "\t" << "{" << std::endl;
238 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
239 std::cout << "\t\t" << "Set" << it->GetFriendlyName() << "(" << "GetDefault" << it->GetFriendlyName() << "());" << std::endl;
242 std::cout << "\t" << "}" << std::endl << std::endl;
245 std::cout << "protected:" << std::endl
246 << "\t" << "virtual void SetField(int id, const Value& value)" << std::endl
247 << "\t" << "{" << std::endl;
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;
253 std::cout << "\t\t" << "switch (";
255 if (!klass.Parent.empty())
256 std::cout << "real_id";
260 std::cout << ") {" << std::endl;
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() << "(";
267 if (it->Attributes & FAEnum)
268 std::cout << "static_cast<" << it->Type << ">(static_cast<int>(";
270 std::cout << "value";
272 if (it->Attributes & FAEnum)
275 std::cout << ");" << std::endl
276 << "\t\t\t\t" << "break;" << std::endl;
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;
284 std::cout << "\t" << "}" << std::endl << std::endl;
287 std::cout << "protected:" << std::endl
288 << "\t" << "virtual Value GetField(int id) const" << std::endl
289 << "\t" << "{" << std::endl;
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;
295 std::cout << "\t\t" << "switch (";
297 if (!klass.Parent.empty())
298 std::cout << "real_id";
302 std::cout << ") {" << std::endl;
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;
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;
315 std::cout << "\t" << "}" << std::endl << std::endl;
318 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
321 if (it->Attributes & FAGetProtected)
326 std::cout << prot << ":" << std::endl
327 << "\t" << it->Type << " Get" << it->GetFriendlyName() << "(void) const" << std::endl
328 << "\t" << "{" << std::endl;
330 if (it->GetAccessor.empty())
331 std::cout << "\t\t" << "return m_" << it->GetFriendlyName() << ";" << std::endl;
333 std::cout << it->GetAccessor << std::endl;
335 std::cout << "\t" << "}" << std::endl << std::endl;
339 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
342 if (it->Attributes & FASetProtected)
344 else if (it->Attributes & FAConfig)
349 std::cout << prot << ":" << std::endl
350 << "\t" << "void Set" << it->GetFriendlyName() << "(const " << it->Type << "& value)" << std::endl
351 << "\t" << "{" << std::endl;
353 if (it->SetAccessor.empty())
354 std::cout << "\t\t" << "m_" << it->GetFriendlyName() << " = value;" << std::endl;
356 std::cout << it->SetAccessor << std::endl;
358 std::cout << "\t" << "}" << std::endl << std::endl;
362 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
365 std::cout << "private:" << std::endl
366 << "\t" << it->Type << " GetDefault" << it->GetFriendlyName() << "(void) const" << std::endl
367 << "\t" << "{" << std::endl;
369 if (it->DefaultAccessor.empty())
370 std::cout << "\t\t" << "return " << it->Type << "();" << std::endl;
372 std::cout << it->DefaultAccessor << std::endl;
374 std::cout << "\t" << "}" << std::endl;
377 /* instance variables */
378 std::cout << "private:" << std::endl;
380 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
381 std::cout << "\t" << it->Type << " m_" << it->GetFriendlyName() << ";" << std::endl;
385 std::cout << "};" << std::endl << std::endl;
388 if (klass.Abstract) {
389 std::cout << "template<>" << std::endl
390 << "struct FactoryHelper<" << klass.Name << ">" << std::endl
392 << "\t" << "Type::Factory GetFactory(void)" << std::endl
393 << "\t" << "{" << std::endl
394 << "\t\t" << "return Type::Factory();"
396 << "};" << std::endl << std::endl;
400 void ClassCompiler::CompileFile(const std::string& path)
402 std::ifstream stream;
403 stream.open(path.c_str(), std::ifstream::in);
406 throw std::invalid_argument("Could not open config file: " + path);
408 return CompileStream(path, &stream);
411 void ClassCompiler::CompileStream(const std::string& path, std::istream *stream)
413 stream->exceptions(std::istream::badbit);
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;
427 ClassCompiler ctx(path, stream);
430 std::cout << "#ifdef _MSC_VER" << std::endl
431 << "#pragma warning ( pop )" << std::endl
432 << "#endif /* _MSC_VER */" << std::endl;