moved common files into source root
[lqt.git] / cpptoxml / main.cpp
blob5f3e9c7af8b5814468005c8764b1957ee2508f5a
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 return ret;
149 #define TAG_CASE(s) case _CodeModelItem::Kind_##s: return #s
151 QString XMLVisitor::XMLTag(CodeModelItem i) {
152 switch (i->kind()) {
153 TAG_CASE(Scope);
154 TAG_CASE(Namespace);
155 TAG_CASE(Member);
156 TAG_CASE(Function);
157 TAG_CASE(Argument);
158 TAG_CASE(Class);
159 TAG_CASE(Enum);
160 TAG_CASE(Enumerator);
161 TAG_CASE(File);
162 TAG_CASE(FunctionDefinition);
163 TAG_CASE(TemplateParameter);
164 TAG_CASE(TypeAlias);
165 TAG_CASE(Variable);
167 return "";
170 QString templateParametersToString (TemplateParameterList list) {
171 QString ret;
172 foreach(TemplateParameterModelItem p,list) {
173 ret = ret + p->name() + ";";
175 return ret;
178 QString XMLVisitor::visit(CodeModelItem i) {
179 QString ret("");
180 ret += XMLTag(i);
182 current_id = ID_STR(i) + " => " + XMLTag(i) + " => " + i->qualifiedName().join("::"); // FIXME: this is debug code
184 ret += ATTR_STR("id", ID_STR(i));
185 ret += ATTR_STR("name", i->name());
186 ret += ATTR_STR("scope", i->scope().join("::"));
187 ret += ATTR_STR("context", current_context.join("::"));
188 // FIXME: is this a dirty hack? yes, it is!
189 if (ArgumentModelItem a = model_dynamic_cast<ArgumentModelItem>(i)) {
190 //ret += ATTR_STR("fullname", current_context.join("::")+"::"+i->qualifiedName().join("::"));
191 } else if (EnumeratorModelItem a = model_dynamic_cast<EnumeratorModelItem>(i)) {
192 ret += ATTR_STR("fullname", current_context.join("::")+"::"+i->qualifiedName().join("::"));
193 } else {
194 ret += ATTR_STR("fullname", i->qualifiedName().join("::"));
197 if (ScopeModelItem s = model_dynamic_cast<ScopeModelItem>(i)) {
198 ret += " members=\"";
200 if (NamespaceModelItem n = model_dynamic_cast<NamespaceModelItem>(i)) {
201 foreach(NamespaceModelItem m, n->namespaces())
202 ret += ID_STR(m).append(" ");
204 if (ScopeModelItem s = model_dynamic_cast<ScopeModelItem>(i)) {
205 foreach(ClassModelItem n, s->classes())
206 ret += ID_STR(n).append(" ");
207 foreach(EnumModelItem n, s->enums())
208 ret += ID_STR(n).append(" ");
209 foreach(FunctionModelItem n, s->functions())
210 ret += ID_STR(n).append(" ");
211 foreach(TypeAliasModelItem n, s->typeAliases())
212 ret += ID_STR(n).append(" ");
213 foreach(VariableModelItem n, s->variables())
214 ret += ID_STR(n).append(" ");
216 if (ScopeModelItem s = model_dynamic_cast<ScopeModelItem>(i)) {
217 ret += "\"";
219 if (MemberModelItem m = model_dynamic_cast<MemberModelItem>(i)) {
220 if (m->isConstant()) ret += ATTR_TRUE("constant");
221 if (m->isVolatile()) ret += ATTR_TRUE("volatile");
222 if (m->isStatic()) ret += ATTR_TRUE("static");
223 if (m->isAuto()) ret += ATTR_TRUE("auto");
224 if (m->isFriend()) ret += ATTR_TRUE("friend");
225 if (m->isRegister()) ret += ATTR_TRUE("register");
226 if (m->isExtern()) ret += ATTR_TRUE("extern");
227 if (m->isMutable()) ret += ATTR_TRUE("mutable");
228 QStringList ownerName = m->qualifiedName();
229 ownerName.pop_back();
230 ret += ATTR_STR("member_of", ownerName.join("::"));
232 if (ClassModelItem c = model_dynamic_cast<ClassModelItem>(current_scope.last()))
233 ret += ATTR_STR("member_of_class", c->qualifiedName().join("::"));
235 switch (m->accessPolicy()) {
236 case CodeModel::Public:
237 ret += ATTR_STR("access", "public");
238 break;
239 case CodeModel::Private:
240 ret += ATTR_STR("access", "private");
241 break;
242 case CodeModel::Protected:
243 ret += ATTR_STR("access", "protected");
244 break;
247 ret += visit(m->type(), m->scope());
248 QString tp = templateParametersToString(m->templateParameters());
249 if (tp!=QString()) ret += ATTR_STR("member_template_parameters", tp);
251 if (FunctionModelItem f = model_dynamic_cast<FunctionModelItem>(i)) {
252 if (f->isVirtual()) ret += ATTR_TRUE("virtual");
253 if (f->isInline()) ret += ATTR_TRUE("inline");
254 if (f->isExplicit()) ret += ATTR_TRUE("explicit");
255 if (f->isAbstract()) ret += ATTR_TRUE("abstract");
256 if (f->isVariadics()) ret += ATTR_TRUE("variadics");
257 //if (i->name()=="destroyed") qDebug() << CodeModel::Normal << CodeModel::Slot << CodeModel::Signal << m->functionType() << i->qualifiedName();
258 switch(f->functionType()) {
259 case CodeModel::Normal:
260 break;
261 case CodeModel::Slot:
262 ret += ATTR_TRUE("slot");
263 break;
264 case CodeModel::Signal:
265 ret += ATTR_TRUE("signal");
266 break;
269 if (ArgumentModelItem a = model_dynamic_cast<ArgumentModelItem>(i)) {
270 ret += visit(a->type(), a->scope());
271 if (a->defaultValue()) {
272 ret += ATTR_TRUE("default");
273 ret += ATTR_STR("defaultvalue", a->defaultValueExpression());
276 if (ClassModelItem c = model_dynamic_cast<ClassModelItem>(i)) {
277 if (c->baseClasses().size()>0) {
278 ret += ATTR_STR("bases", c->baseClasses().join(";").append(";"));
280 switch(c->classType()) {
281 case CodeModel::Class:
282 ret += ATTR_STR("class_type", QString("class"));
283 break;
284 case CodeModel::Struct:
285 ret += ATTR_STR("class_type", QString("struct"));
286 break;
287 case CodeModel::Union:
288 ret += ATTR_STR("class_type", QString("union"));
289 break;
291 QString tp = templateParametersToString(c->templateParameters());
292 if (tp!=QString()) ret += ATTR_STR("member_template_parameters", tp);
293 // TODO also list propertyDeclarations (maybe in content?)
295 if (EnumModelItem e = model_dynamic_cast<EnumModelItem>(i)) {
296 switch (e->accessPolicy()) {
297 case CodeModel::Public:
298 ret += ATTR_STR("access", "public");
299 break;
300 case CodeModel::Private:
301 ret += ATTR_STR("access", "private");
302 break;
303 case CodeModel::Protected:
304 ret += ATTR_STR("access", "protected");
305 break;
308 if (EnumeratorModelItem e = model_dynamic_cast<EnumeratorModelItem>(i)) {
309 ret += e->value().prepend(" value=\"").append("\"");
311 if (TypeAliasModelItem t = model_dynamic_cast<TypeAliasModelItem>(i)) {
312 ret += visit(t->type(), t->scope());
315 ret.replace('>', "&gt;");
316 ret.replace('<', "&lt;");
317 ret = "<" + ret + " >\n";
320 // content of the entry:
321 // - Arguments of functions
322 // - members of scopes
323 // - enumeration values
325 if (NamespaceModelItem n = model_dynamic_cast<NamespaceModelItem>(i)) {
326 foreach(NamespaceModelItem m, n->namespaces())
327 ret += visit(model_static_cast<CodeModelItem>(m));
329 if (i->kind() & _CodeModelItem::Kind_Scope) {
330 //qDebug() << ID_STR(i) << i->name() << current_context;
331 //CodeModelItem os = current_scope; // save old outer scope
332 if (!i->name().isEmpty()) { current_context << i->name(); current_scope << i; }
333 foreach(ClassModelItem n, model_dynamic_cast<ScopeModelItem>(i)->classes())
334 ret += visit(model_static_cast<CodeModelItem>(n));
335 foreach(EnumModelItem n, model_dynamic_cast<ScopeModelItem>(i)->enums())
336 ret += visit(model_static_cast<CodeModelItem>(n));
337 foreach(FunctionModelItem n, model_dynamic_cast<ScopeModelItem>(i)->functions())
338 ret += visit(model_static_cast<CodeModelItem>(n));
339 foreach(TypeAliasModelItem n, model_dynamic_cast<ScopeModelItem>(i)->typeAliases())
340 ret += visit(model_static_cast<CodeModelItem>(n));
341 foreach(VariableModelItem n, model_dynamic_cast<ScopeModelItem>(i)->variables())
342 ret += visit(model_static_cast<CodeModelItem>(n));
343 if (!i->name().isEmpty()) { current_context.removeLast(); current_scope.pop_back(); }
345 if (FunctionModelItem f = model_dynamic_cast<FunctionModelItem>(i)) {
346 foreach(ArgumentModelItem a, f->arguments())
347 ret += visit(model_static_cast<CodeModelItem>(a));
349 if (EnumModelItem e = model_dynamic_cast<EnumModelItem>(i)) {
350 QString last = "0";
351 foreach(EnumeratorModelItem n, model_dynamic_cast<EnumModelItem>(i)->enumerators()) {
352 if (n->value() == QString()) n->setValue(last.append("+1"));
353 ret += visit(model_static_cast<CodeModelItem>(n));
354 last = n->value();
359 ret += "</";
360 ret += XMLTag(i);
361 ret += ">\n";
362 return ret;
365 int main (int argc, char **argv) {
366 bool onlyPreprocess = false;
367 bool dontResolve = false;
368 QString configName;
369 QString sourceName;
371 QStringList options;
372 for (int i=1;i<argc;i++) options << argv[i];
373 int i;
374 if ((i=options.indexOf("-C"))!=-1) {
375 if (options.count() > i+1) {
376 configName = options.at(i+1);
377 options.removeAt(i+1);
379 options.removeAt(i);
381 if ((i=options.indexOf("-P"))!=-1) {
382 onlyPreprocess = true;
383 options.removeAt(i);
385 if ((i=options.indexOf("-R"))!=-1) {
386 dontResolve = true;
387 options.removeAt(i);
389 if (options.count()>1) return 37;
390 sourceName = options.at(0);
392 QByteArray contents;
394 Preprocessor pp;
395 QStringList inclist;
397 QString qtdir = getenv ("QTDIR");
398 if (qtdir.isEmpty()) {
399 fprintf(stderr, "Generator requires QTDIR to be set\n");
400 return false;
403 qtdir += "/include";
405 QString currentDir = QDir::current().absolutePath();
406 QFileInfo sourceInfo(sourceName);
407 //QDir::setCurrent(sourceInfo.absolutePath());
409 inclist << (sourceInfo.absolutePath());
410 inclist << (QDir::convertSeparators(qtdir));
411 inclist << (QDir::convertSeparators(qtdir + "/QtXml"));
412 inclist << (QDir::convertSeparators(qtdir + "/QtNetwork"));
413 inclist << (QDir::convertSeparators(qtdir + "/QtCore"));
414 inclist << (QDir::convertSeparators(qtdir + "/QtGui"));
415 inclist << (QDir::convertSeparators(qtdir + "/QtOpenGL"));
416 //qDebug() << inclist;
418 pp.addIncludePaths(inclist);
419 pp.processFile(sourceName, configName);
420 //qDebug() << pp.macroNames();
421 contents = pp.result();
422 //qDebug() << contents;
423 //QTextStream(stdout) << contents;
425 if (onlyPreprocess) {
426 QTextStream(stdout) << contents;
427 } else {
428 Control control;
429 Parser p(&control);
430 pool __pool;
432 TranslationUnitAST *ast = p.parse(contents, contents.size(), &__pool);
434 CodeModel model;
435 Binder binder(&model, p.location());
436 FileModelItem f_model = binder.run(ast);
438 XMLVisitor visitor((CodeModelItem)f_model, !dontResolve);
439 QTextStream(stdout) << visitor.visit(model_static_cast<CodeModelItem>(f_model));
442 return 0;