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 std::cout << "\t\t" << "switch (";
173 if (!klass.Parent.empty())
174 std::cout << "real_id";
178 std::cout << ") {" << std::endl;
181 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
182 std::cout << "\t\t\t" << "case " << num << ":" << std::endl
183 << "\t\t\t\t" << "return Field(" << num << ", \"" << it->Name << "\", " << it->Attributes << ");" << std::endl;
187 std::cout << "\t\t\t" << "default:" << std::endl
188 << "\t\t\t\t" << "throw std::runtime_error(\"Invalid field ID.\");" << std::endl
189 << "\t\t" << "}" << std::endl;
191 std::cout << "\t" << "}" << std::endl << std::endl;
194 std::cout << "\t" << "virtual int GetFieldCount(void) const" << std::endl
195 << "\t" << "{" << std::endl
196 << "\t\t" << "return StaticGetFieldCount();" << std::endl
197 << "\t" << "}" << std::endl << std::endl;
199 /* StaticGetFieldCount */
200 std::cout << "\t" << "static int StaticGetFieldCount(void)" << std::endl
201 << "\t" << "{" << std::endl
202 << "\t\t" << "return " << klass.Fields.size();
204 if (!klass.Parent.empty())
205 std::cout << " + " << "TypeImpl<" << klass.Parent << ">::StaticGetFieldCount()";
207 std::cout << ";" << std::endl
208 << "\t" << "}" << std::endl << std::endl;
210 std::cout << "};" << std::endl << std::endl;
213 std::cout << "template<>" << std::endl
214 << "class ObjectImpl<" << klass.Name << ">"
215 << " : public " << (klass.Parent.empty() ? "Object" : klass.Parent) << std::endl
217 << "public:" << std::endl
218 << "\t" << "DECLARE_PTR_TYPEDEFS(ObjectImpl<" << klass.Name << ">);" << std::endl << std::endl;
220 /* GetReflectionType */
221 std::cout << "\t" << "virtual const Type *GetReflectionType(void) const" << std::endl
222 << "\t" << "{" << std::endl
223 << "\t\t" << "return Type::GetByName(\"" << klass.Name << "\");" << std::endl
224 << "\t" << "}" << std::endl << std::endl;
226 if (!klass.Fields.empty()) {
228 std::cout << "public:" << std::endl
229 << "\t" << "ObjectImpl<" << klass.Name << ">(void)" << std::endl
230 << "\t" << "{" << std::endl;
232 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
233 std::cout << "\t\t" << "Set" << it->GetFriendlyName() << "(" << "GetDefault" << it->GetFriendlyName() << "());" << std::endl;
236 std::cout << "\t" << "}" << std::endl << std::endl;
239 std::cout << "protected:" << std::endl
240 << "\t" << "virtual void SetField(int id, const Value& value)" << std::endl
241 << "\t" << "{" << std::endl;
243 if (!klass.Parent.empty())
244 std::cout << "\t\t" << "int real_id = id - TypeImpl<" << klass.Parent << ">::StaticGetFieldCount(); " << std::endl
245 << "\t\t" << "if (real_id < 0) { " << klass.Parent << "::SetField(id, value); return; }" << std::endl;
247 std::cout << "\t\t" << "switch (";
249 if (!klass.Parent.empty())
250 std::cout << "real_id";
254 std::cout << ") {" << std::endl;
257 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
258 std::cout << "\t\t\t" << "case " << num << ":" << std::endl
259 << "\t\t\t\t" << "Set" << it->GetFriendlyName() << "(";
261 if (it->Attributes & FAEnum)
262 std::cout << "static_cast<" << it->Type << ">(static_cast<int>(";
264 std::cout << "value";
266 if (it->Attributes & FAEnum)
269 std::cout << ");" << std::endl
270 << "\t\t\t\t" << "break;" << std::endl;
274 std::cout << "\t\t\t" << "default:" << std::endl
275 << "\t\t\t\t" << "throw std::runtime_error(\"Invalid field ID.\");" << std::endl
276 << "\t\t" << "}" << std::endl;
278 std::cout << "\t" << "}" << std::endl << std::endl;
281 std::cout << "protected:" << std::endl
282 << "\t" << "virtual Value GetField(int id) const" << std::endl
283 << "\t" << "{" << std::endl;
285 if (!klass.Parent.empty())
286 std::cout << "\t\t" << "int real_id = id - TypeImpl<" << klass.Parent << ">::StaticGetFieldCount(); " << std::endl
287 << "\t\t" << "if (real_id < 0) { return " << klass.Parent << "::GetField(id); }" << std::endl;
289 std::cout << "\t\t" << "switch (";
291 if (!klass.Parent.empty())
292 std::cout << "real_id";
296 std::cout << ") {" << std::endl;
299 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
300 std::cout << "\t\t\t" << "case " << num << ":" << std::endl
301 << "\t\t\t\t" << "return Get" << it->GetFriendlyName() << "();" << std::endl;
305 std::cout << "\t\t\t" << "default:" << std::endl
306 << "\t\t\t\t" << "throw std::runtime_error(\"Invalid field ID.\");" << std::endl
307 << "\t\t" << "}" << std::endl;
309 std::cout << "\t" << "}" << std::endl << std::endl;
312 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
315 if (it->Attributes & FAGetProtected)
320 std::cout << prot << ":" << std::endl
321 << "\t" << it->Type << " Get" << it->GetFriendlyName() << "(void) const" << std::endl
322 << "\t" << "{" << std::endl;
324 if (it->GetAccessor.empty())
325 std::cout << "\t\t" << "return m_" << it->GetFriendlyName() << ";" << std::endl;
327 std::cout << it->GetAccessor << std::endl;
329 std::cout << "\t" << "}" << std::endl << std::endl;
333 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
336 if (it->Attributes & FASetProtected)
338 else if (it->Attributes & FAConfig)
343 std::cout << prot << ":" << std::endl
344 << "\t" << "void Set" << it->GetFriendlyName() << "(const " << it->Type << "& value)" << std::endl
345 << "\t" << "{" << std::endl;
347 if (it->SetAccessor.empty())
348 std::cout << "\t\t" << "m_" << it->GetFriendlyName() << " = value;" << std::endl;
350 std::cout << it->SetAccessor << std::endl;
352 std::cout << "\t" << "}" << std::endl << std::endl;
356 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
359 std::cout << "private:" << std::endl
360 << "\t" << it->Type << " GetDefault" << it->GetFriendlyName() << "(void) const" << std::endl
361 << "\t" << "{" << std::endl;
363 if (it->DefaultAccessor.empty())
364 std::cout << "\t\t" << "return " << it->Type << "();" << std::endl;
366 std::cout << it->DefaultAccessor << std::endl;
368 std::cout << "\t" << "}" << std::endl;
371 /* instance variables */
372 std::cout << "private:" << std::endl;
374 for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
375 std::cout << "\t" << it->Type << " m_" << it->GetFriendlyName() << ";" << std::endl;
379 std::cout << "};" << std::endl << std::endl;
382 if (klass.Abstract) {
383 std::cout << "template<>" << std::endl
384 << "struct FactoryHelper<" << klass.Name << ">" << std::endl
386 << "\t" << "Type::Factory GetFactory(void)" << std::endl
387 << "\t" << "{" << std::endl
388 << "\t\t" << "return Type::Factory();"
390 << "};" << std::endl << std::endl;
394 void ClassCompiler::CompileFile(const std::string& path)
396 std::ifstream stream;
397 stream.open(path.c_str(), std::ifstream::in);
400 throw std::invalid_argument("Could not open config file: " + path);
402 return CompileStream(path, &stream);
405 void ClassCompiler::CompileStream(const std::string& path, std::istream *stream)
407 stream->exceptions(std::istream::badbit);
409 std::cout << "#include \"base/object.h\"" << std::endl
410 << "#include \"base/type.h\"" << std::endl
411 << "#include \"base/debug.h\"" << std::endl
412 << "#include \"base/value.h\"" << std::endl
413 << "#include \"base/array.h\"" << std::endl
414 << "#include \"base/dictionary.h\"" << std::endl << std::endl
415 << "#ifdef _MSC_VER" << std::endl
416 << "#pragma warning( push )" << std::endl
417 << "#pragma warning( disable : 4244 )" << std::endl
418 << "#pragma warning( disable : 4800 )" << std::endl
419 << "#endif /* _MSC_VER */" << std::endl << std::endl;
421 ClassCompiler ctx(path, stream);
424 std::cout << "#ifdef _MSC_VER" << std::endl
425 << "#pragma warning ( pop )" << std::endl
426 << "#endif /* _MSC_VER */" << std::endl;