closed brace for qt_metacall function
[lqt.git] / cpptoxml / main.cpp
blob2dbf6fc2cbceb4f8b657c363a6804078293fa0e9
1 /*
2 * Copyright (c) 2007-2008 Mauro Iazzi
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use,
8 * copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following
11 * conditions:
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
27 #include <iostream>
28 #include <typeinfo>
30 #include "binder.h"
31 #include "codemodel.h"
32 #include "control.h"
33 #include "parser.h"
34 #include "preprocessor.h"
36 #include <QByteArray>
37 #include <QFile>
38 #include <QTextCodec>
39 #include <QTextStream>
41 #include <QObject>
42 #include <QDir>
44 #include <QDebug>
46 #define ID_STR(i) (QString("_").append(QString::number(i->creationId())))
47 #define ATTR_STR(n, v) ( QString(" ") + n + QString("=\"") + v + QString("\"") )
48 #define ATTR_NUM(n, v) ( (QString::number(v)).prepend(" " n "=\"").append("\"") )
49 #define ATTR_TRUE(n) ( ATTR_NUM(n, 1) )
51 using namespace std;
53 class XMLVisitor {
54 private:
55 bool resolve_types;
56 QString current_id;
57 QStringList current_context;
58 QList<CodeModelItem> current_scope;
59 CodeModelItem outer_scope;
60 public:
61 XMLVisitor(CodeModelItem c, bool r = true):
62 resolve_types(r), current_scope(), outer_scope(c) {
63 current_scope << c;
65 QString XMLTag(CodeModelItem);
66 TypeInfo solve(const TypeInfo&, QStringList);
67 TypeInfo simplifyType (TypeInfo const &, CodeModelItem __scope);
68 QString visit(const TypeInfo&, QStringList);
69 QString visit(CodeModelItem);
71 template <typename T> QString visit(T) {
72 std::cerr << "unimplemented CodeModelItem: " << typeid(T).name() << std::endl;
73 return "";
79 TypeInfo XMLVisitor::simplifyType (TypeInfo const &__type, CodeModelItem __scope)
81 CodeModel *__model = __scope->model ();
82 Q_ASSERT (__model != 0);
83 TypeInfo t;
84 for (int i=0;i<__type.qualifiedName().size();i++) {
85 QStringList qname = t.qualifiedName();
86 qname << __type.qualifiedName().at(i);
87 t.setQualifiedName(qname);
88 //t = this->solve(t, __scope->qualifiedName());
89 QString oldt = t.toString();
90 t = t.resolveType(t, __scope);
91 if (t.toString()!=oldt) qDebug() << oldt << " --> " << t.toString();
94 TypeInfo otherType = __type;
95 otherType.setQualifiedName(t.qualifiedName());
97 return otherType;
102 TypeInfo XMLVisitor::solve(const TypeInfo& t, QStringList scope) {
103 (void)scope;
104 if (!resolve_types) return t;
105 TypeInfo tt(t);
106 for (QList<CodeModelItem>::const_iterator i=current_scope.begin();
107 i<current_scope.end();
108 i++) {
109 TypeInfo ttt = tt;
110 //qDebug() << tt.toString() << ttt.toString();
111 Q_ASSERT(ttt==tt);
112 do {
113 tt = ttt;
114 ttt = ttt.resolveType(tt, *i);
115 } while (ttt!=tt);
118 return tt;
121 QString XMLVisitor::visit(const TypeInfo& t, QStringList scope) {
122 //t = t.resolveType(t, t.scope());
124 QString oldt = t.toString();
125 TypeInfo tt = solve(t, scope);
126 //tt = simplifyType(tt, current_scope.first());
127 while (oldt!=tt.toString()) {
128 oldt = tt.toString();
129 tt = solve(tt, scope);
131 //if (oldt!=tt.toString()) qDebug() << oldt << " -> " << tt.toString();
133 QString ret(" type_name=\"");
134 ret += tt.toString().append("\"");
135 ret += " type_base=\"";
136 ret += tt.qualifiedName().join("::").append("\"");
137 if (tt.isConstant()) ret += ATTR_TRUE("type_constant");
138 if (tt.isVolatile()) ret += ATTR_TRUE("type_volatile");
139 if (tt.isReference()) ret += ATTR_TRUE("type_reference");
140 if (tt.indirections()>0) ret += ATTR_NUM("indirections", tt.indirections());
142 QStringList arr = tt.arrayElements();
143 QString tmp = arr.join(",");
144 if (!tmp.isEmpty()) ret += " array=\"" + tmp + "\"";
146 if (tt.isFunctionPointer()) ret += " function_pointer=\"1\"";
148 return ret;
151 #define TAG_CASE(s) case _CodeModelItem::Kind_##s: return #s
153 QString XMLVisitor::XMLTag(CodeModelItem i) {
154 switch (i->kind()) {
155 TAG_CASE(Scope);
156 TAG_CASE(Namespace);
157 TAG_CASE(Member);
158 TAG_CASE(Function);
159 TAG_CASE(Argument);
160 TAG_CASE(Class);
161 TAG_CASE(Enum);
162 TAG_CASE(Enumerator);
163 TAG_CASE(File);
164 TAG_CASE(FunctionDefinition);
165 TAG_CASE(TemplateParameter);
166 TAG_CASE(TypeAlias);
167 TAG_CASE(Variable);
169 return "";
172 QString templateParametersToString (TemplateParameterList list) {
173 QString ret;
174 foreach(TemplateParameterModelItem p,list) {
175 ret = ret + p->name() + ";";
177 return ret;
180 QString XMLVisitor::visit(CodeModelItem i) {
181 QString ret("");
182 ret += XMLTag(i);
184 current_id = ID_STR(i) + " => " + XMLTag(i) + " => " + i->qualifiedName().join("::"); // FIXME: this is debug code
186 ret += ATTR_STR("id", ID_STR(i));
187 ret += ATTR_STR("name", i->name());
188 ret += ATTR_STR("scope", i->scope().join("::"));
189 ret += ATTR_STR("context", current_context.join("::"));
190 // FIXME: is this a dirty hack? yes, it is!
191 if (ArgumentModelItem a = model_dynamic_cast<ArgumentModelItem>(i)) {
192 //ret += ATTR_STR("fullname", current_context.join("::")+"::"+i->qualifiedName().join("::"));
193 } else if (EnumeratorModelItem a = model_dynamic_cast<EnumeratorModelItem>(i)) {
194 ret += ATTR_STR("fullname", current_context.join("::")+"::"+i->qualifiedName().join("::"));
195 } else {
196 ret += ATTR_STR("fullname", i->qualifiedName().join("::"));
199 if (ScopeModelItem s = model_dynamic_cast<ScopeModelItem>(i)) {
200 ret += " members=\"";
202 if (NamespaceModelItem n = model_dynamic_cast<NamespaceModelItem>(i)) {
203 foreach(NamespaceModelItem m, n->namespaces())
204 ret += ID_STR(m).append(" ");
206 if (ScopeModelItem s = model_dynamic_cast<ScopeModelItem>(i)) {
207 foreach(ClassModelItem n, s->classes())
208 ret += ID_STR(n).append(" ");
209 foreach(EnumModelItem n, s->enums())
210 ret += ID_STR(n).append(" ");
211 foreach(FunctionModelItem n, s->functions())
212 ret += ID_STR(n).append(" ");
213 foreach(TypeAliasModelItem n, s->typeAliases())
214 ret += ID_STR(n).append(" ");
215 foreach(VariableModelItem n, s->variables())
216 ret += ID_STR(n).append(" ");
218 if (ScopeModelItem s = model_dynamic_cast<ScopeModelItem>(i)) {
219 ret += "\"";
221 if (MemberModelItem m = model_dynamic_cast<MemberModelItem>(i)) {
222 if (m->isConstant()) ret += ATTR_TRUE("constant");
223 if (m->isVolatile()) ret += ATTR_TRUE("volatile");
224 if (m->isStatic()) ret += ATTR_TRUE("static");
225 if (m->isAuto()) ret += ATTR_TRUE("auto");
226 if (m->isFriend()) ret += ATTR_TRUE("friend");
227 if (m->isRegister()) ret += ATTR_TRUE("register");
228 if (m->isExtern()) ret += ATTR_TRUE("extern");
229 if (m->isMutable()) ret += ATTR_TRUE("mutable");
230 QStringList ownerName = m->qualifiedName();
231 ownerName.pop_back();
232 ret += ATTR_STR("member_of", ownerName.join("::"));
234 if (ClassModelItem c = model_dynamic_cast<ClassModelItem>(current_scope.last()))
235 ret += ATTR_STR("member_of_class", c->qualifiedName().join("::"));
237 switch (m->accessPolicy()) {
238 case CodeModel::Public:
239 ret += ATTR_STR("access", "public");
240 break;
241 case CodeModel::Private:
242 ret += ATTR_STR("access", "private");
243 break;
244 case CodeModel::Protected:
245 ret += ATTR_STR("access", "protected");
246 break;
249 ret += visit(m->type(), m->scope());
250 QString tp = templateParametersToString(m->templateParameters());
251 if (tp!=QString()) ret += ATTR_STR("member_template_parameters", tp);
253 if (FunctionModelItem f = model_dynamic_cast<FunctionModelItem>(i)) {
254 if (f->isVirtual()) ret += ATTR_TRUE("virtual");
255 if (f->isInline()) ret += ATTR_TRUE("inline");
256 if (f->isExplicit()) ret += ATTR_TRUE("explicit");
257 if (f->isAbstract()) ret += ATTR_TRUE("abstract");
258 if (f->isVariadics()) ret += ATTR_TRUE("variadics");
259 //if (i->name()=="destroyed") qDebug() << CodeModel::Normal << CodeModel::Slot << CodeModel::Signal << m->functionType() << i->qualifiedName();
260 switch(f->functionType()) {
261 case CodeModel::Normal:
262 break;
263 case CodeModel::Slot:
264 ret += ATTR_TRUE("slot");
265 break;
266 case CodeModel::Signal:
267 ret += ATTR_TRUE("signal");
268 break;
271 if (ArgumentModelItem a = model_dynamic_cast<ArgumentModelItem>(i)) {
272 ret += visit(a->type(), a->scope());
273 if (a->defaultValue()) {
274 ret += ATTR_TRUE("default");
275 ret += ATTR_STR("defaultvalue", a->defaultValueExpression());
278 if (ClassModelItem c = model_dynamic_cast<ClassModelItem>(i)) {
279 if (c->baseClasses().size()>0) {
280 ret += ATTR_STR("bases", c->baseClasses().join(";").append(";"));
282 switch(c->classType()) {
283 case CodeModel::Class:
284 ret += ATTR_STR("class_type", QString("class"));
285 break;
286 case CodeModel::Struct:
287 ret += ATTR_STR("class_type", QString("struct"));
288 break;
289 case CodeModel::Union:
290 ret += ATTR_STR("class_type", QString("union"));
291 break;
293 QString tp = templateParametersToString(c->templateParameters());
294 if (tp!=QString()) ret += ATTR_STR("member_template_parameters", tp);
295 // TODO also list propertyDeclarations (maybe in content?)
297 if (EnumModelItem e = model_dynamic_cast<EnumModelItem>(i)) {
298 switch (e->accessPolicy()) {
299 case CodeModel::Public:
300 ret += ATTR_STR("access", "public");
301 break;
302 case CodeModel::Private:
303 ret += ATTR_STR("access", "private");
304 break;
305 case CodeModel::Protected:
306 ret += ATTR_STR("access", "protected");
307 break;
310 if (EnumeratorModelItem e = model_dynamic_cast<EnumeratorModelItem>(i)) {
311 ret += e->value().prepend(" value=\"").append("\"");
313 if (TypeAliasModelItem t = model_dynamic_cast<TypeAliasModelItem>(i)) {
314 ret += visit(t->type(), t->scope());
317 ret.replace('&', "&amp;");
318 ret.replace('>', "&gt;");
319 ret.replace('<', "&lt;");
320 ret = "<" + ret + " >\n";
323 // content of the entry:
324 // - Arguments of functions
325 // - members of scopes
326 // - enumeration values
328 if (NamespaceModelItem n = model_dynamic_cast<NamespaceModelItem>(i)) {
329 foreach(NamespaceModelItem m, n->namespaces())
330 ret += visit(model_static_cast<CodeModelItem>(m));
332 if (i->kind() & _CodeModelItem::Kind_Scope) {
333 //qDebug() << ID_STR(i) << i->name() << current_context;
334 //CodeModelItem os = current_scope; // save old outer scope
335 if (!i->name().isEmpty()) { current_context << i->name(); current_scope << i; }
336 foreach(ClassModelItem n, model_dynamic_cast<ScopeModelItem>(i)->classes())
337 ret += visit(model_static_cast<CodeModelItem>(n));
338 foreach(EnumModelItem n, model_dynamic_cast<ScopeModelItem>(i)->enums())
339 ret += visit(model_static_cast<CodeModelItem>(n));
340 foreach(FunctionModelItem n, model_dynamic_cast<ScopeModelItem>(i)->functions())
341 ret += visit(model_static_cast<CodeModelItem>(n));
342 foreach(TypeAliasModelItem n, model_dynamic_cast<ScopeModelItem>(i)->typeAliases())
343 ret += visit(model_static_cast<CodeModelItem>(n));
344 foreach(VariableModelItem n, model_dynamic_cast<ScopeModelItem>(i)->variables())
345 ret += visit(model_static_cast<CodeModelItem>(n));
346 if (!i->name().isEmpty()) { current_context.removeLast(); current_scope.pop_back(); }
348 if (FunctionModelItem f = model_dynamic_cast<FunctionModelItem>(i)) {
349 foreach(ArgumentModelItem a, f->arguments())
350 ret += visit(model_static_cast<CodeModelItem>(a));
352 if (EnumModelItem e = model_dynamic_cast<EnumModelItem>(i)) {
353 QString last = "0";
354 foreach(EnumeratorModelItem n, model_dynamic_cast<EnumModelItem>(i)->enumerators()) {
355 if (n->value() == QString()) n->setValue(last.append("+1"));
356 ret += visit(model_static_cast<CodeModelItem>(n));
357 last = n->value();
362 ret += "</";
363 ret += XMLTag(i);
364 ret += ">\n";
365 return ret;
368 int main (int argc, char **argv) {
369 bool onlyPreprocess = false;
370 bool dontResolve = false;
371 QString configName;
372 QString sourceName;
374 QStringList options;
375 for (int i=1;i<argc;i++) options << argv[i];
376 int i;
377 if ((i=options.indexOf("-C"))!=-1) {
378 if (options.count() > i+1) {
379 configName = QDir::fromNativeSeparators(options.at(i+1));
380 options.removeAt(i+1);
382 options.removeAt(i);
384 if ((i=options.indexOf("-P"))!=-1) {
385 onlyPreprocess = true;
386 options.removeAt(i);
388 if ((i=options.indexOf("-R"))!=-1) {
389 dontResolve = true;
390 options.removeAt(i);
392 if (options.count()>1) return 37;
393 sourceName = QDir::fromNativeSeparators(options.at(0));
395 QByteArray contents;
397 Preprocessor pp;
398 QStringList inclist;
400 QString qtdir = QDir::fromNativeSeparators(getenv("QT_INCLUDE"));
401 if (qtdir.isEmpty()) {
402 fprintf(stderr, "Generator requires QT_INCLUDE to be set\n");
403 return false;
406 QString currentDir = QDir::current().absolutePath();
407 QFileInfo sourceInfo(sourceName);
408 //QDir::setCurrent(sourceInfo.absolutePath());
410 inclist << (sourceInfo.absolutePath());
411 inclist << (QDir::convertSeparators(qtdir));
412 inclist << (QDir::convertSeparators(qtdir + "/QtXml"));
413 inclist << (QDir::convertSeparators(qtdir + "/QtNetwork"));
414 inclist << (QDir::convertSeparators(qtdir + "/QtCore"));
415 inclist << (QDir::convertSeparators(qtdir + "/QtGui"));
416 inclist << (QDir::convertSeparators(qtdir + "/QtOpenGL"));
417 //qDebug() << inclist;
419 pp.addIncludePaths(inclist);
420 pp.processFile(sourceName, configName);
421 //qDebug() << pp.macroNames();
422 contents = pp.result();
423 //qDebug() << contents;
424 //QTextStream(stdout) << contents;
426 if (onlyPreprocess) {
427 QTextStream(stdout) << contents;
428 } else {
429 Control control;
430 Parser p(&control);
431 pool __pool;
433 TranslationUnitAST *ast = p.parse(contents, contents.size(), &__pool);
435 CodeModel model;
436 Binder binder(&model, p.location());
437 FileModelItem f_model = binder.run(ast);
439 XMLVisitor visitor((CodeModelItem)f_model, !dontResolve);
440 QTextStream(stdout) << visitor.visit(model_static_cast<CodeModelItem>(f_model));
443 return 0;