~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/tools/moc/moc.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
 
4
**
 
5
** This file is part of the tools applications of the Qt Toolkit.
 
6
**
 
7
** This file may be distributed under the terms of the Q Public License
 
8
** as defined by Trolltech AS of Norway and appearing in the file
 
9
** LICENSE.QPL included in the packaging of this file.
 
10
**
 
11
** This file may be distributed and/or modified under the terms of the
 
12
** GNU General Public License version 2 as published by the Free Software
 
13
** Foundation and appearing in the file LICENSE.GPL included in the
 
14
** packaging of this file.
 
15
**
 
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
 
17
**   information about Qt Commercial License Agreements.
 
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
 
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
 
20
**
 
21
** Contact info@trolltech.com if any conditions of this licensing are
 
22
** not clear to you.
 
23
**
 
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
26
**
 
27
****************************************************************************/
 
28
 
 
29
#include "moc.h"
 
30
#include "generator.h"
 
31
#include "qdatetime.h"
 
32
#include "utils.h"
 
33
#include "outputrevision.h"
 
34
#include <stdio.h>
 
35
#include <stdlib.h>
 
36
 
 
37
// WARNING: a copy of this function is in qmetaobject.cpp
 
38
static QByteArray normalizeTypeInternal(const char *t, const char *e, bool fixScope = true, bool adjustConst = true)
 
39
{
 
40
    int len = e - t;
 
41
    if (strncmp("void", t, len) == 0)
 
42
        return QByteArray();
 
43
    /*
 
44
      Convert 'char const *' into 'const char *'. Start at index 1,
 
45
      not 0, because 'const char *' is already OK.
 
46
    */
 
47
    QByteArray constbuf;
 
48
    for (int i = 1; i < len; i++) {
 
49
        if ( t[i] == 'c'
 
50
             && strncmp(t + i + 1, "onst", 4) == 0
 
51
             && (i + 5 >= len || !is_ident_char(t[i + 5]))
 
52
             && !is_ident_char(t[i-1])
 
53
            ) {
 
54
            constbuf = QByteArray(t, len);
 
55
            if (is_space(t[i-1]))
 
56
                constbuf.remove(i-1, 6);
 
57
            else
 
58
                constbuf.remove(i, 5);
 
59
            constbuf.prepend("const ");
 
60
            t = constbuf.data();
 
61
            e = constbuf.data() + constbuf.length();
 
62
            break;
 
63
        }
 
64
        /*
 
65
          We musn't convert 'char * const *' into 'const char **'
 
66
          and we must beware of 'Bar<const Bla>'.
 
67
        */
 
68
        if (t[i] == '&' || t[i] == '*' ||t[i] == '<')
 
69
            break;
 
70
    }
 
71
    if (adjustConst && e > t + 6 && strncmp("const ", t, 6) == 0) {
 
72
        if (*(e-1) == '&') { // treat const reference as value
 
73
            t += 6;
 
74
            --e;
 
75
        } else if (is_ident_char(*(e-1))) { // treat const value as value
 
76
            t += 6;
 
77
        }
 
78
    }
 
79
    QByteArray result;
 
80
    result.reserve(len);
 
81
 
 
82
    // some type substitutions for 'unsigned x'
 
83
    if (strncmp("unsigned ", t, 9) == 0) {
 
84
        if (strncmp("int", t+9, 3) == 0) {
 
85
            t += 9+3;
 
86
            result += "uint";
 
87
        } else if (strncmp("long", t+9, 4) == 0) {
 
88
            t += 9+4;
 
89
            result += "ulong";
 
90
        }
 
91
    }
 
92
 
 
93
    while (t != e) {
 
94
        char c = *t++;
 
95
        if (fixScope && c == ':' && *t == ':' ) {
 
96
            ++t;
 
97
            c = *t++;
 
98
            int i = result.size() - 1;
 
99
            while (i >= 0 && is_ident_char(result.at(i)))
 
100
                   --i;
 
101
            result.resize(i + 1);
 
102
        }
 
103
        result += c;
 
104
        if (c == '<') {
 
105
            //template recursion
 
106
            const char* tt = t;
 
107
            int templdepth = 1;
 
108
            while (t != e) {
 
109
                c = *t++;
 
110
                if (c == '<')
 
111
                    ++templdepth;
 
112
                if (c == '>')
 
113
                    --templdepth;
 
114
                if (templdepth == 0) {
 
115
                    result += normalizeTypeInternal(tt, t-1, fixScope, false);
 
116
                    result += c;
 
117
                    if (*t == '>')
 
118
                        result += ' '; // avoid >>
 
119
                    break;
 
120
                }
 
121
            }
 
122
        }
 
123
    }
 
124
 
 
125
    return result;
 
126
}
 
127
 
 
128
// only moc needs this function
 
129
QByteArray normalizeType(const char *s, bool fixScope)
 
130
{
 
131
    int len = qstrlen(s);
 
132
    char stackbuf[64];
 
133
    char *buf = (len >= 64 ? new char[len] : stackbuf);
 
134
    char *d = buf;
 
135
    char last = 0;
 
136
    while(*s && is_space(*s))
 
137
        s++;
 
138
    while (*s) {
 
139
        while (*s && !is_space(*s))
 
140
            last = *d++ = *s++;
 
141
        while (*s && is_space(*s))
 
142
            s++;
 
143
        if (*s && is_ident_char(*s) && is_ident_char(last))
 
144
            last = *d++ = ' ';
 
145
    }
 
146
    *d = '\0';
 
147
    QByteArray result = normalizeTypeInternal(buf, d, fixScope);
 
148
    if (buf != stackbuf)
 
149
        delete [] buf;
 
150
    return result;
 
151
}
 
152
 
 
153
static const char *error_msg = 0;
 
154
 
 
155
#ifdef Q_CC_MSVC
 
156
#define ErrorFormatString "%s(%d): "
 
157
#else
 
158
#define ErrorFormatString "%s:%d: "
 
159
#endif
 
160
 
 
161
void Moc::error(int rollback) {
 
162
    index -= rollback;
 
163
    error();
 
164
}
 
165
void Moc::error(const char *msg) {
 
166
    if (msg || error_msg)
 
167
        qWarning(ErrorFormatString "Error: %s",
 
168
               currentFilenames.top().constData(), symbol().lineNum, msg?msg:error_msg);
 
169
    else
 
170
        qWarning(ErrorFormatString "Parse error at \"%s\"",
 
171
               currentFilenames.top().constData(), symbol().lineNum, symbol().lexem().data());
 
172
    exit(EXIT_FAILURE);
 
173
}
 
174
 
 
175
void Moc::warning(const char *msg) {
 
176
    if (displayWarnings && msg)
 
177
        fprintf(stderr, ErrorFormatString "Warning: %s\n",
 
178
                filename.constData(), qMax(0, symbol().lineNum), msg);
 
179
}
 
180
 
 
181
bool Moc::until(Token target) {
 
182
    int braceCount = 0;
 
183
    int brackCount = 0;
 
184
    int parenCount = 0;
 
185
    int angleCount = 0;
 
186
    if (index) {
 
187
        switch(symbols.at(index-1).token) {
 
188
        case LBRACE: ++braceCount; break;
 
189
        case LBRACK: ++brackCount; break;
 
190
        case LPAREN: ++parenCount; break;
 
191
        case LANGLE: ++angleCount; break;
 
192
        default: ;
 
193
        }
 
194
    }
 
195
    while (index < symbols.size()) {
 
196
        Token t = symbols.at(index++).token;
 
197
        switch (t) {
 
198
        case LBRACE: ++braceCount; break;
 
199
        case RBRACE: --braceCount; break;
 
200
        case LBRACK: ++brackCount; break;
 
201
        case RBRACK: --brackCount; break;
 
202
        case LPAREN: ++parenCount; break;
 
203
        case RPAREN: --parenCount; break;
 
204
        case LANGLE: ++angleCount; break;
 
205
        case RANGLE: --angleCount; break;
 
206
        default: break;
 
207
        }
 
208
        if (t == target
 
209
            && braceCount <= 0
 
210
            && brackCount <= 0
 
211
            && parenCount <= 0
 
212
            && (target != RANGLE || angleCount <= 0))
 
213
            return true;
 
214
 
 
215
        if (braceCount < 0 || brackCount < 0 || parenCount < 0
 
216
            || (target == RANGLE && angleCount < 0)) {
 
217
            --index;
 
218
            break;
 
219
        }
 
220
    }
 
221
    return false;
 
222
}
 
223
 
 
224
QByteArray Moc::lexemUntil(Token target)
 
225
{
 
226
    int from = index;
 
227
    until(target);
 
228
    QByteArray s;
 
229
    while (from <= index) {
 
230
        QByteArray n = symbols.at(from++-1).lexem();
 
231
        if (s.size() && n.size()
 
232
            && is_ident_char(s.at(s.size()-1))
 
233
            && is_ident_char(n.at(0)))
 
234
            s += ' ';
 
235
        s += n;
 
236
    }
 
237
    return s;
 
238
}
 
239
 
 
240
bool Moc::parseClassHead(ClassDef *def)
 
241
{
 
242
    // figure out whether this is a class declaration, or only a
 
243
    // forward or variable declaration.
 
244
    int i = 0;
 
245
    Token token;
 
246
    do {
 
247
        token = lookup(i++);
 
248
        if (token == COLON || token == LBRACE)
 
249
            break;
 
250
        if (token == SEMIC || token == RANGLE)
 
251
            return false;
 
252
    } while (token);
 
253
 
 
254
    next(IDENTIFIER);
 
255
    QByteArray name = lexem();
 
256
 
 
257
    // support "class IDENT name" and "class IDENT(IDENT) name"
 
258
    if (test(LPAREN)) {
 
259
        until(RPAREN);
 
260
        next(IDENTIFIER);
 
261
        name = lexem();
 
262
    } else  if (test(IDENTIFIER)) {
 
263
        name = lexem();
 
264
    }
 
265
 
 
266
    def->qualified += name;
 
267
    while (test(SCOPE)) {
 
268
        def->qualified += lexem();
 
269
        if (test(IDENTIFIER)) {
 
270
            name = lexem();
 
271
            def->qualified += name;
 
272
        }
 
273
    }
 
274
    def->classname = name;
 
275
    if (test(COLON)) {
 
276
        do {
 
277
            test(VIRTUAL);
 
278
            FunctionDef::Access access = FunctionDef::Public;
 
279
            if (test(PRIVATE))
 
280
                access = FunctionDef::Private;
 
281
            else if (test(PROTECTED))
 
282
                access = FunctionDef::Protected;
 
283
            else
 
284
                test(PUBLIC);
 
285
            test(VIRTUAL);
 
286
            def->superclassList += qMakePair(parseType(), access);
 
287
        } while (test(COMMA));
 
288
    }
 
289
    next(LBRACE);
 
290
    def->begin = index - 1;
 
291
    until(RBRACE);
 
292
    def->end = index ;
 
293
    index = def->begin + 1;
 
294
    return true;
 
295
};
 
296
 
 
297
QByteArray Moc::parseType()
 
298
{
 
299
    QByteArray s;
 
300
    while (test(CONST) || test(VOLATILE) || test(SIGNED) || test(UNSIGNED)) {
 
301
        s += lexem();
 
302
        s += ' ';
 
303
    }
 
304
    test(ENUM) || test(CLASS) || test(STRUCT);
 
305
    for(;;) {
 
306
        switch (next()) {
 
307
        case IDENTIFIER:
 
308
        case CHAR:
 
309
        case SHORT:
 
310
        case INT:
 
311
        case LONG:
 
312
        case FLOAT:
 
313
        case DOUBLE:
 
314
        case VOID:
 
315
        case BOOL:
 
316
            s += lexem();
 
317
            break;
 
318
        default:
 
319
            prev();
 
320
            ;
 
321
        }
 
322
        if (test(LANGLE)) {
 
323
            QByteArray templ = lexemUntil(RANGLE);
 
324
            for (int i = 0; i < templ.size(); ++i) {
 
325
                s += templ.at(i);
 
326
                if (templ.at(i) == '>' && i < templ.size()-1 && templ.at(i+1) == '>')
 
327
                    s += ' ';
 
328
            }
 
329
        }
 
330
        if (test(SCOPE))
 
331
            s += lexem();
 
332
        else
 
333
            break;
 
334
    }
 
335
    while (test(CONST) || test(VOLATILE) || test(SIGNED) || test(UNSIGNED)
 
336
           || test(STAR) || test(AND)) {
 
337
        s += ' ';
 
338
        s += lexem();
 
339
    }
 
340
    return s;
 
341
}
 
342
 
 
343
bool Moc::parseEnum(EnumDef *def)
 
344
{
 
345
    if (!test(IDENTIFIER))
 
346
        return false; // anonymous enum
 
347
    def->name = lexem();
 
348
    if (!test(LBRACE))
 
349
        return false;
 
350
    do {
 
351
        if (lookup() == RBRACE) // accept trailing comma
 
352
            break;
 
353
        next(IDENTIFIER);
 
354
        def->values += lexem();
 
355
    } while (test(EQ) ? until(COMMA) : test(COMMA));
 
356
    next(RBRACE);
 
357
    return true;
 
358
}
 
359
 
 
360
void Moc::parseFunctionArguments(FunctionDef *def)
 
361
{
 
362
    Q_UNUSED(def);
 
363
    while (hasNext()) {
 
364
        ArgumentDef  arg;
 
365
        arg.type = parseType();
 
366
        if (arg.type == "void")
 
367
            break;
 
368
        if (test(IDENTIFIER))
 
369
            arg.name = lexem();
 
370
        if (test(LBRACK))
 
371
            arg.rightType += lexemUntil(RBRACK);
 
372
        if (test(CONST) || test(VOLATILE)) {
 
373
            arg.rightType += ' ';
 
374
            arg.rightType += lexem();
 
375
        }
 
376
        arg.normalizedType = normalizeType(arg.type + ' ' + arg.rightType);
 
377
        if (test(EQ))
 
378
            arg.isDefault = true;
 
379
        def->arguments += arg;
 
380
        if (!until(COMMA))
 
381
            break;
 
382
    }
 
383
}
 
384
 
 
385
void Moc::parseFunction(FunctionDef *def, bool inMacro)
 
386
{
 
387
    def->isVirtual = test(VIRTUAL);
 
388
    while (test(INLINE) || test(STATIC))
 
389
        ;
 
390
    bool templateFunction = (lookup() == TEMPLATE);
 
391
    def->type = parseType();
 
392
    if (def->type.isEmpty()) {
 
393
        if (templateFunction)
 
394
            error("Template function as signal or slot");
 
395
        else
 
396
            error();
 
397
}
 
398
    if (test(LPAREN)) {
 
399
        def->name = def->type;
 
400
        def->type = "int";
 
401
    } else {
 
402
        def->name = parseType();
 
403
        while (!def->name.isEmpty() && lookup() != LPAREN) {
 
404
            if (def->type == "QT_MOC_COMPAT" || def->type == "QT3_SUPPORT")
 
405
                def->isCompat = true;
 
406
            else if (def->type == "Q_INVOKABLE")
 
407
                def->isInvokable = true;
 
408
            else if (def->type == "Q_SCRIPTABLE")
 
409
                def->isInvokable = def->isScriptable = true;
 
410
            else {
 
411
                if (!def->tag.isEmpty())
 
412
                    def->tag += ' ';
 
413
                def->tag += def->type;
 
414
            }
 
415
            def->type = def->name;
 
416
            def->name = parseType();
 
417
        }
 
418
        next(LPAREN, "Not a signal or slot declaration");
 
419
    }
 
420
 
 
421
    def->normalizedType = normalizeType(def->type);
 
422
 
 
423
    if (!test(RPAREN)) {
 
424
        parseFunctionArguments(def);
 
425
        next(RPAREN);
 
426
    }
 
427
    def->isConst = test(CONST);
 
428
    if (inMacro) {
 
429
        next(RPAREN);
 
430
    } else {
 
431
        if (test(SEMIC))
 
432
            ;
 
433
        else if ((def->inlineCode = test(LBRACE)))
 
434
            until(RBRACE);
 
435
        else if (test(EQ))
 
436
            until(SEMIC);
 
437
        else
 
438
            error();
 
439
    }
 
440
}
 
441
 
 
442
// like parseFunction, but never aborts with an error
 
443
bool Moc::parseMaybeFunction(FunctionDef *def)
 
444
{
 
445
    def->type = parseType();
 
446
    if (def->type.isEmpty())
 
447
        return false;
 
448
    if (test(LPAREN)) {
 
449
        def->name = def->type;
 
450
        def->type = "int";
 
451
    } else {
 
452
        def->name = parseType();
 
453
        while (!def->name.isEmpty() && lookup() != LPAREN) {
 
454
            if (def->type == "QT_MOC_COMPAT" || def->type == "QT3_SUPPORT")
 
455
                def->isCompat = true;
 
456
            else if (def->type == "Q_INVOKABLE")
 
457
                def->isInvokable = true;
 
458
            else if (def->type == "Q_SCRIPTABLE")
 
459
                def->isInvokable = def->isScriptable = true;
 
460
            else {
 
461
                if (!def->tag.isEmpty())
 
462
                    def->tag += ' ';
 
463
                def->tag += def->type;
 
464
            }
 
465
            def->type = def->name;
 
466
            def->name = parseType();
 
467
        }
 
468
        if (!test(LPAREN))
 
469
            return false;
 
470
    }
 
471
 
 
472
    def->normalizedType = normalizeType(def->type);
 
473
 
 
474
    if (!test(RPAREN)) {
 
475
        parseFunctionArguments(def);
 
476
        if (!test(RPAREN))
 
477
            return false;
 
478
    }
 
479
    def->isConst = test(CONST);
 
480
    return true;
 
481
}
 
482
 
 
483
 
 
484
void Moc::parse()
 
485
{
 
486
    currentFilenames.push(filename);
 
487
 
 
488
    QList<NamespaceDef> namespaceList;
 
489
    bool templateClass = false;
 
490
    while (hasNext()) {
 
491
        Token t = next();
 
492
        if (t == NAMESPACE) {
 
493
            int rewind = index;
 
494
            if (test(IDENTIFIER) && !test(SEMIC)) {
 
495
                NamespaceDef def;
 
496
                def.name = lexem();
 
497
                next(LBRACE);
 
498
                def.begin = index - 1;
 
499
                until(RBRACE);
 
500
                def.end = index;
 
501
                index = def.begin + 1;
 
502
                namespaceList += def;
 
503
            }
 
504
            index = rewind;
 
505
        } else if (t == SEMIC || t == RBRACE) {
 
506
            templateClass = false;
 
507
        } else if (t == TEMPLATE) {
 
508
            templateClass = true;
 
509
        } else if (t == MOC_INCLUDE_BEGIN) {
 
510
            next(STRING_LITERAL);
 
511
            currentFilenames.push(symbol().unquotedLexem());
 
512
        } else if (t == MOC_INCLUDE_END) {
 
513
            currentFilenames.pop();
 
514
        } else if (t == Q_DECLARE_INTERFACE_TOKEN) {
 
515
            parseDeclareInterface();
 
516
        } else if (t == USING && test(NAMESPACE)) {
 
517
            while (test(SCOPE) || test(IDENTIFIER))
 
518
                ;
 
519
            next(SEMIC);
 
520
        }
 
521
        if (t != CLASS || currentFilenames.size() > 1)
 
522
            continue;
 
523
        ClassDef def;
 
524
        FunctionDef::Access access = FunctionDef::Private;
 
525
        if (parseClassHead(&def)) {
 
526
            for (int i = namespaceList.size() - 1; i >= 0; --i)
 
527
                if (inNamespace(&namespaceList.at(i)))
 
528
                    def.qualified.prepend(namespaceList.at(i).name + "::");
 
529
            while (inClass(&def) && hasNext()) {
 
530
                switch ((t = next())) {
 
531
                case PRIVATE:
 
532
                    access = FunctionDef::Private;
 
533
                    if (test(SIGNALS))
 
534
                        error("Signals cannot have access specifier");
 
535
                    break;
 
536
                case PROTECTED:
 
537
                    access = FunctionDef::Protected;
 
538
                    if (test(SIGNALS))
 
539
                        error("Signals cannot have access specifier");
 
540
                    break;
 
541
                case PUBLIC:
 
542
                    access = FunctionDef::Public;
 
543
                    if (test(SIGNALS))
 
544
                        error("Signals cannot have access specifier");
 
545
                    break;
 
546
                case CLASS: {
 
547
                    ClassDef nestedDef;
 
548
                    if (parseClassHead(&nestedDef)) {
 
549
                        while (inClass(&nestedDef) && inClass(&def)) {
 
550
                            t = next();
 
551
                            if (t >= Q_META_TOKEN_BEGIN && t < Q_META_TOKEN_END)
 
552
                                error("Meta object features not supported for nested classes");
 
553
                        }
 
554
                    }
 
555
                } break;
 
556
                case SIGNALS:
 
557
                    parseSignals(&def);
 
558
                    break;
 
559
                case SLOTS:
 
560
                    switch (lookup(-1)) {
 
561
                    case PUBLIC:
 
562
                    case PROTECTED:
 
563
                    case PRIVATE:
 
564
                        parseSlots(&def, access);
 
565
                        break;
 
566
                    default:
 
567
                        error("Missing access specifier for slots");
 
568
                    }
 
569
                    break;
 
570
                case Q_OBJECT_TOKEN:
 
571
                    def.hasQObject = true;
 
572
                    if (templateClass)
 
573
                        error("Template classes not supported by Q_OBJECT");
 
574
                    if (def.classname != "Qt" && def.classname != "QObject" && def.superclassList.isEmpty())
 
575
                        error("Class contains Q_OBJECT macro but does not inherit from QObject");
 
576
                    break;
 
577
                case Q_GADGET_TOKEN:
 
578
                    def.hasQGadget = true;
 
579
                    if (templateClass)
 
580
                        error("Template classes not supported by Q_GADGET");
 
581
                    break;
 
582
                case Q_PROPERTY_TOKEN:
 
583
                    parseProperty(&def);
 
584
                    break;
 
585
                case Q_ENUMS_TOKEN:
 
586
                    parseEnumOrFlag(&def, false);
 
587
                    break;
 
588
                case Q_FLAGS_TOKEN:
 
589
                    parseEnumOrFlag(&def, true);
 
590
                    break;
 
591
                case Q_DECLARE_FLAGS_TOKEN:
 
592
                    parseFlag(&def);
 
593
                    break;
 
594
                case Q_CLASSINFO_TOKEN:
 
595
                    parseClassInfo(&def);
 
596
                    break;
 
597
                case Q_INTERFACES_TOKEN:
 
598
                    parseInterfaces(&def);
 
599
                    break;
 
600
                case Q_PRIVATE_SLOT_TOKEN:
 
601
                    parseSlotInPrivate(&def, access);
 
602
                    break;
 
603
                case ENUM: {
 
604
                    EnumDef enumDef;
 
605
                    if (parseEnum(&enumDef))
 
606
                        def.enumList += enumDef;
 
607
                } break;
 
608
                default:
 
609
                    FunctionDef funcDef;
 
610
                    funcDef.access = access;
 
611
                    int rewind = index;
 
612
                    if (parseMaybeFunction(&funcDef)) {
 
613
                        if (access == FunctionDef::Public)
 
614
                            def.publicList += funcDef;
 
615
                        if (funcDef.isInvokable) {
 
616
                            def.methodList += funcDef;
 
617
                            while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
 
618
                                funcDef.wasCloned = true;
 
619
                                funcDef.arguments.removeLast();
 
620
                                def.methodList += funcDef;
 
621
                            }
 
622
                        }
 
623
                    } else {
 
624
                        index = rewind;
 
625
                    }
 
626
                }
 
627
            }
 
628
 
 
629
            next(RBRACE);
 
630
 
 
631
            if (!def.hasQObject && def.signalList.isEmpty() && def.slotList.isEmpty()
 
632
                && def.propertyList.isEmpty() && def.enumDeclarations.isEmpty())
 
633
                continue; // no meta object code required
 
634
 
 
635
 
 
636
            if (!def.hasQObject && !def.hasQGadget)
 
637
                error("Class declarations lacks Q_OBJECT macro.");
 
638
 
 
639
            classList += def;
 
640
        }
 
641
    }
 
642
 
 
643
}
 
644
 
 
645
void Moc::generate(FILE *out)
 
646
{
 
647
 
 
648
    QDateTime dt = QDateTime::currentDateTime();
 
649
    QByteArray dstr = dt.toString().toLatin1();
 
650
    QByteArray fn = filename;
 
651
    int i = filename.length()-1;
 
652
    while (i>0 && filename[i-1] != '/' && filename[i-1] != '\\')
 
653
        --i;                                // skip path
 
654
    if (i >= 0)
 
655
        fn = filename.mid(i);
 
656
    fprintf(out, "/****************************************************************************\n"
 
657
            "** Meta object code from reading C++ file '%s'\n**\n" , (const char*)fn);
 
658
    fprintf(out, "** Created: %s\n"
 
659
            "**      by: The Qt Meta Object Compiler version %d (Qt %s)\n**\n" , dstr.data(), mocOutputRevision, QT_VERSION_STR);
 
660
    fprintf(out, "** WARNING! All changes made in this file will be lost!\n"
 
661
            "*****************************************************************************/\n\n");
 
662
 
 
663
 
 
664
    if (!noInclude) {
 
665
        if (includePath.size() && includePath.right(1) != "/")
 
666
            includePath += "/";
 
667
        for (int i = 0; i < includeFiles.size(); ++i) {
 
668
            QByteArray inc = includeFiles.at(i);
 
669
            if (inc[0] != '<' && inc[0] != '"') {
 
670
                if (includePath.size() && includePath != "./")
 
671
                    inc.prepend(includePath);
 
672
                inc = "\"" + inc + "\"";
 
673
            }
 
674
            fprintf(out, "#include %s\n", inc.constData());
 
675
        }
 
676
    }
 
677
    if (classList.size() && classList.first().classname == "Qt")
 
678
        fprintf(out, "#include <QtCore/qobject.h>\n");
 
679
 
 
680
    fprintf(out, "#if !defined(Q_MOC_OUTPUT_REVISION)\n"
 
681
            "#error \"The header file '%s' doesn't include <QObject>.\"\n", (const char *)fn);
 
682
    fprintf(out, "#elif Q_MOC_OUTPUT_REVISION != %d\n", mocOutputRevision);
 
683
    fprintf(out, "#error \"This file was generated using the moc from %s."
 
684
            " It\"\n#error \"cannot be used with the include files from"
 
685
            " this version of Qt.\"\n#error \"(The moc has changed too"
 
686
            " much.)\"\n", QT_VERSION_STR);
 
687
    fprintf(out, "#endif\n\n");
 
688
 
 
689
 
 
690
    for (i = 0; i < classList.size(); ++i) {
 
691
        Generator generator(out, &classList[i]);
 
692
        generator.generateCode();
 
693
    }
 
694
}
 
695
 
 
696
 
 
697
 
 
698
void Moc::parseSlots(ClassDef *def, FunctionDef::Access access)
 
699
{
 
700
    next(COLON);
 
701
    while (inClass(def) && hasNext()) {
 
702
        switch (next()) {
 
703
        case PUBLIC:
 
704
        case PROTECTED:
 
705
        case PRIVATE:
 
706
        case SIGNALS:
 
707
        case SLOTS:
 
708
            prev();
 
709
            return;
 
710
        case SEMIC:
 
711
            continue;
 
712
        default:
 
713
            prev();
 
714
        }
 
715
 
 
716
        FunctionDef funcDef;
 
717
        funcDef.access = access;
 
718
        parseFunction(&funcDef);
 
719
        def->slotList += funcDef;
 
720
        while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
 
721
            funcDef.wasCloned = true;
 
722
            funcDef.arguments.removeLast();
 
723
            def->slotList += funcDef;
 
724
        }
 
725
    }
 
726
}
 
727
 
 
728
void Moc::parseSignals(ClassDef *def)
 
729
{
 
730
    next(COLON);
 
731
    while (inClass(def) && hasNext()) {
 
732
        switch (next()) {
 
733
        case PUBLIC:
 
734
        case PROTECTED:
 
735
        case PRIVATE:
 
736
        case SIGNALS:
 
737
        case SLOTS:
 
738
            prev();
 
739
            return;
 
740
        case SEMIC:
 
741
            continue;
 
742
        default:
 
743
            prev();
 
744
        }
 
745
        FunctionDef funcDef;
 
746
        funcDef.access = FunctionDef::Protected;
 
747
        parseFunction(&funcDef);
 
748
        if (funcDef.isVirtual)
 
749
            error("Signals cannot be declared virtual");
 
750
        if (funcDef.isConst)
 
751
            error("Signals cannot have const qualifier");
 
752
        if (funcDef.inlineCode)
 
753
            error("Not a signal declaration");
 
754
        def->signalList += funcDef;
 
755
        while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
 
756
            funcDef.wasCloned = true;
 
757
            funcDef.arguments.removeLast();
 
758
            def->signalList += funcDef;
 
759
        }
 
760
    }
 
761
}
 
762
 
 
763
 
 
764
void Moc::parseProperty(ClassDef *def)
 
765
{
 
766
    next(LPAREN);
 
767
    PropertyDef propDef;
 
768
    QByteArray type = parseType();
 
769
    if (type.isEmpty())
 
770
        error();
 
771
    propDef.designable = propDef.scriptable = propDef.stored = "true";
 
772
    /*
 
773
      The Q_PROPERTY construct cannot contain any commas, since
 
774
      commas separate macro arguments. We therefore expect users
 
775
      to type "QMap" instead of "QMap<QString, QVariant>". For
 
776
      coherence, we also expect the same for
 
777
      QValueList<QVariant>, the other template class supported by
 
778
      QVariant.
 
779
    */
 
780
    type = normalizeType(type);
 
781
    if (type == "QMap")
 
782
        type = "QMap<QString,QVariant>";
 
783
    else if (type == "QValueList")
 
784
        type = "QValueList<QVariant>";
 
785
    else if (type == "LongLong")
 
786
        type = "qlonglong";
 
787
    else if (type == "ULongLong")
 
788
        type = "qulonglong";
 
789
    propDef.type = type;
 
790
 
 
791
    next();
 
792
    propDef.name = lexem();
 
793
    while (test(IDENTIFIER)) {
 
794
        QByteArray l = lexem();
 
795
        QByteArray v, v2;
 
796
        if (test(LPAREN)) {
 
797
            v = lexemUntil(RPAREN);
 
798
        } else {
 
799
            next(IDENTIFIER);
 
800
            v = lexem();
 
801
            if (test(LPAREN))
 
802
                v2 = lexemUntil(RPAREN);
 
803
            else if (v != "true" && v != "false")
 
804
                v2 = "()";
 
805
        }
 
806
        switch (l[0]) {
 
807
        case 'R':
 
808
            if (l == "READ")
 
809
                propDef.read = v;
 
810
            else if (l == "RESET")
 
811
                propDef.reset = v + v2;
 
812
            else
 
813
                error(2);
 
814
            break;
 
815
        case 'S':
 
816
            if (l == "SCRIPTABLE")
 
817
                propDef.scriptable = v + v2;
 
818
            else if (l == "STORED")
 
819
                propDef.stored = v + v2;
 
820
            else
 
821
                error(2);
 
822
            break;
 
823
        case 'W': if (l != "WRITE") error(2);
 
824
            propDef.write = v;
 
825
            break;
 
826
        case 'D': if (l != "DESIGNABLE") error(2);
 
827
            propDef.designable = v + v2;
 
828
            break;
 
829
        case 'E': if (l != "EDITABLE") error(2);
 
830
            propDef.editable = v + v2;
 
831
            break;
 
832
        case 'N': if (l != "NOTIFY") error(2);
 
833
            break;
 
834
        default:
 
835
            error(2);
 
836
        }
 
837
    }
 
838
    next(RPAREN);
 
839
    def->propertyList += propDef;
 
840
}
 
841
 
 
842
void Moc::parseEnumOrFlag(ClassDef *def, bool isFlag)
 
843
{
 
844
    next(LPAREN);
 
845
    QByteArray identifier;
 
846
    while (test(IDENTIFIER)) {
 
847
        identifier = lexem();
 
848
        while (test(SCOPE) && test(IDENTIFIER)) {
 
849
            identifier += "::";
 
850
            identifier += lexem();
 
851
        }
 
852
        def->enumDeclarations[identifier] = isFlag;
 
853
    }
 
854
    next(RPAREN);
 
855
}
 
856
 
 
857
void Moc::parseFlag(ClassDef *def)
 
858
{
 
859
    next(LPAREN);
 
860
    QByteArray flagName, enumName;
 
861
    while (test(IDENTIFIER)) {
 
862
        flagName = lexem();
 
863
        while (test(SCOPE) && test(IDENTIFIER)) {
 
864
            flagName += "::";
 
865
            flagName += lexem();
 
866
        }
 
867
    }
 
868
    next(COMMA);
 
869
    while (test(IDENTIFIER)) {
 
870
        enumName = lexem();
 
871
        while (test(SCOPE) && test(IDENTIFIER)) {
 
872
            enumName += "::";
 
873
            enumName += lexem();
 
874
        }
 
875
    }
 
876
 
 
877
    def->flagAliases.insert(enumName, flagName);
 
878
    next(RPAREN);
 
879
}
 
880
 
 
881
void Moc::parseClassInfo(ClassDef *def)
 
882
{
 
883
    next(LPAREN);
 
884
    ClassInfoDef infoDef;
 
885
    next(STRING_LITERAL);
 
886
    infoDef.name = symbol().unquotedLexem();
 
887
    next(COMMA);
 
888
    next(STRING_LITERAL);
 
889
    infoDef.value = symbol().unquotedLexem();
 
890
    def->classInfoList += infoDef;
 
891
}
 
892
 
 
893
void Moc::parseInterfaces(ClassDef *def)
 
894
{
 
895
    next(LPAREN);
 
896
    while (test(IDENTIFIER)) {
 
897
        QList<ClassDef::Interface> iface;
 
898
        iface += ClassDef::Interface(lexem());
 
899
        while (test(SCOPE)) {
 
900
            iface.last().className += lexem();
 
901
            next(IDENTIFIER);
 
902
            iface.last().className += lexem();
 
903
        }
 
904
        while (test(COLON)) {
 
905
            next(IDENTIFIER);
 
906
            iface += ClassDef::Interface(lexem());
 
907
            while (test(SCOPE)) {
 
908
                iface.last().className += lexem();
 
909
                next(IDENTIFIER);
 
910
                iface.last().className += lexem();
 
911
            }
 
912
        }
 
913
        // resolve from classnames to interface ids
 
914
        for (int i = 0; i < iface.count(); ++i) {
 
915
            const QByteArray iid = interface2IdMap.value(iface.at(i).className);
 
916
            if (iid.isEmpty())
 
917
                error("Undefined interface");
 
918
 
 
919
            iface[i].interfaceId = iid;
 
920
        }
 
921
        def->interfaceList += iface;
 
922
    }
 
923
    next(RPAREN);
 
924
}
 
925
 
 
926
void Moc::parseDeclareInterface()
 
927
{
 
928
    next(LPAREN);
 
929
    QByteArray interface;
 
930
    next(IDENTIFIER);
 
931
    interface += lexem();
 
932
    while (test(SCOPE)) {
 
933
        interface += lexem();
 
934
        next(IDENTIFIER);
 
935
        interface += lexem();
 
936
    }
 
937
    next(COMMA);
 
938
    QByteArray iid;
 
939
    if (test(STRING_LITERAL)) {
 
940
        iid = symbol().lexem();
 
941
    } else {
 
942
        next(IDENTIFIER);
 
943
        iid = lexem();
 
944
    }
 
945
    interface2IdMap.insert(interface, iid);
 
946
    next(RPAREN);
 
947
}
 
948
 
 
949
void Moc::parseSlotInPrivate(ClassDef *def, FunctionDef::Access access)
 
950
{
 
951
    next(LPAREN);
 
952
    FunctionDef funcDef;
 
953
    next(IDENTIFIER);
 
954
    funcDef.inPrivateClass = lexem();
 
955
    // also allow void functions
 
956
    if (test(LPAREN)) {
 
957
        next(RPAREN);
 
958
        funcDef.inPrivateClass += "()";
 
959
    }
 
960
    next(COMMA);
 
961
    funcDef.access = access;
 
962
    parseFunction(&funcDef, true);
 
963
    def->slotList += funcDef;
 
964
    while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
 
965
        funcDef.wasCloned = true;
 
966
        funcDef.arguments.removeLast();
 
967
        def->slotList += funcDef;
 
968
    }
 
969
}
 
970