qmljstypedescriptionreader.cpp 23.7 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
Tobias Hunger's avatar
Tobias Hunger committed
2
**
3
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
Tobias Hunger's avatar
Tobias Hunger committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
Tobias Hunger's avatar
Tobias Hunger committed
7
**
hjk's avatar
hjk committed
8
9
10
11
12
13
14
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
Tobias Hunger's avatar
Tobias Hunger committed
15
16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
18
19
20
21
22
23
24
25
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
Tobias Hunger's avatar
Tobias Hunger committed
26
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
Tobias Hunger's avatar
Tobias Hunger committed
29

30
31
32
33
34
35
#include "qmljstypedescriptionreader.h"

#include "parser/qmljsparser_p.h"
#include "parser/qmljslexer_p.h"
#include "parser/qmljsengine_p.h"

36
#include "qmljsinterpreter.h"
37
#include "qmljsutils.h"
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

using namespace QmlJS;
using namespace QmlJS::AST;
using namespace LanguageUtils;

TypeDescriptionReader::TypeDescriptionReader(const QString &data)
    : _source(data)
    , _objects(0)
{
}

TypeDescriptionReader::~TypeDescriptionReader()
{
}

53
54
55
bool TypeDescriptionReader::operator()(
        QHash<QString, FakeMetaObject::ConstPtr> *objects,
        QList<ModuleApiInfo> *moduleApis)
56
57
58
59
60
61
{
    Engine engine;

    Lexer lexer(&engine);
    Parser parser(&engine);

62
    lexer.setCode(_source, /*line = */ 1, /*qmlMode = */true);
63
64

    if (!parser.parse()) {
65
        _errorMessage = QString::fromLatin1("%1:%2: %3").arg(
66
67
68
69
70
71
72
                    QString::number(parser.errorLineNumber()),
                    QString::number(parser.errorColumnNumber()),
                    parser.errorMessage());
        return false;
    }

    _objects = objects;
73
    _moduleApis = moduleApis;
74
75
76
77
78
79
80
81
82
83
    readDocument(parser.ast());

    return _errorMessage.isEmpty();
}

QString TypeDescriptionReader::errorMessage() const
{
    return _errorMessage;
}

84
85
86
87
88
QString TypeDescriptionReader::warningMessage() const
{
    return _warningMessage;
}

89
90
91
void TypeDescriptionReader::readDocument(UiProgram *ast)
{
    if (!ast) {
Leena Miettinen's avatar
Leena Miettinen committed
92
        addError(SourceLocation(), tr("Could not parse document."));
93
94
95
        return;
    }

Fawzi Mohamed's avatar
Fawzi Mohamed committed
96
    if (!ast->headers || ast->headers->next || !AST::cast<AST::UiImport *>(ast->headers->headerItem)) {
Leena Miettinen's avatar
Leena Miettinen committed
97
        addError(SourceLocation(), tr("Expected a single import."));
98
99
100
        return;
    }

Fawzi Mohamed's avatar
Fawzi Mohamed committed
101
    UiImport *import = AST::cast<AST::UiImport *>(ast->headers->headerItem);
102
    if (toString(import->importUri) != QLatin1String("QtQuick.tooling")) {
Leena Miettinen's avatar
Leena Miettinen committed
103
        addError(import->importToken, tr("Expected import of QtQuick.tooling."));
104
105
106
107
108
109
110
111
112
113
        return;
    }

    ComponentVersion version;
    const QString versionString = _source.mid(import->versionToken.offset, import->versionToken.length);
    const int dotIdx = versionString.indexOf(QLatin1Char('.'));
    if (dotIdx != -1) {
        version = ComponentVersion(versionString.left(dotIdx).toInt(),
                                   versionString.mid(dotIdx + 1).toInt());
    }
114
115
    if (version.majorVersion() != 1) {
        addError(import->versionToken, tr("Major version different from 1 not supported."));
116
117
        return;
    }
118
119
    if (version.minorVersion() > 1)
        addWarning(import->versionToken, tr("Reading only version 1.1 parts."));
120
121

    if (!ast->members || !ast->members->member || ast->members->next) {
Leena Miettinen's avatar
Leena Miettinen committed
122
        addError(SourceLocation(), tr("Expected document to contain a single object definition."));
123
124
125
126
127
        return;
    }

    UiObjectDefinition *module = dynamic_cast<UiObjectDefinition *>(ast->members->member);
    if (!module) {
Leena Miettinen's avatar
Leena Miettinen committed
128
        addError(SourceLocation(), tr("Expected document to contain a single object definition."));
129
130
131
        return;
    }

132
    if (toString(module->qualifiedTypeNameId) != QLatin1String("Module")) {
Leena Miettinen's avatar
Leena Miettinen committed
133
        addError(SourceLocation(), tr("Expected document to contain a Module {} member."));
134
135
136
137
138
139
140
141
142
143
144
        return;
    }

    readModule(module);
}

void TypeDescriptionReader::readModule(UiObjectDefinition *ast)
{
    for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
        UiObjectMember *member = it->member;
        UiObjectDefinition *component = dynamic_cast<UiObjectDefinition *>(member);
145
146
147

        QString typeName;
        if (component)
148
            typeName = toString(component->qualifiedTypeNameId);
149

150
151
        if (!component || (typeName != QLatin1String("Component") && typeName != QLatin1String("ModuleApi"))) {
            addWarning(member->firstSourceLocation(),
Leena Miettinen's avatar
Leena Miettinen committed
152
                       tr("Expected only Component and ModuleApi object definitions."));
153
            continue;
154
155
        }

156
        if (typeName == QLatin1String("Component"))
157
            readComponent(component);
158
        else if (typeName == QLatin1String("ModuleApi"))
159
            readModuleApi(component);
160
161
162
163
164
    }
}

void TypeDescriptionReader::addError(const SourceLocation &loc, const QString &message)
{
165
    _errorMessage += QString::fromLatin1("%1:%2: %3\n").arg(
166
167
168
169
170
                QString::number(loc.startLine),
                QString::number(loc.startColumn),
                message);
}

171
172
void TypeDescriptionReader::addWarning(const SourceLocation &loc, const QString &message)
{
173
    _warningMessage += QString::fromLatin1("%1:%2: %3\n").arg(
174
175
176
177
178
                QString::number(loc.startLine),
                QString::number(loc.startColumn),
                message);
}

179
180
181
182
183
184
185
186
187
void TypeDescriptionReader::readComponent(UiObjectDefinition *ast)
{
    FakeMetaObject::Ptr fmo(new FakeMetaObject);

    for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
        UiObjectMember *member = it->member;
        UiObjectDefinition *component = dynamic_cast<UiObjectDefinition *>(member);
        UiScriptBinding *script = dynamic_cast<UiScriptBinding *>(member);
        if (component) {
188
            QString name = toString(component->qualifiedTypeNameId);
189
            if (name == QLatin1String("Property"))
190
                readProperty(component, fmo);
191
            else if (name == QLatin1String("Method") || name == QLatin1String("Signal"))
192
                readSignalOrMethod(component, name == QLatin1String("Method"), fmo);
193
            else if (name == QLatin1String("Enum"))
194
                readEnum(component, fmo);
195
            else
Leena Miettinen's avatar
Leena Miettinen committed
196
                addWarning(component->firstSourceLocation(), tr("Expected only Property, Method, Signal and Enum object definitions."));
197
        } else if (script) {
198
            QString name = toString(script->qualifiedId);
199
            if (name == QLatin1String("name")) {
200
                fmo->setClassName(readStringBinding(script));
201
            } else if (name == QLatin1String("prototype")) {
202
                fmo->setSuperclassName(readStringBinding(script));
203
            } else if (name == QLatin1String("defaultProperty")) {
204
                fmo->setDefaultPropertyName(readStringBinding(script));
205
            } else if (name == QLatin1String("exports")) {
206
                readExports(script, fmo);
207
            } else if (name == QLatin1String("exportMetaObjectRevisions")) {
208
                readMetaObjectRevisions(script, fmo);
209
            } else if (name == QLatin1String("attachedType")) {
210
                fmo->setAttachedTypeName(readStringBinding(script));
211
            } else {
212
                addWarning(script->firstSourceLocation(),
213
                           tr("Expected only name, prototype, defaultProperty, attachedType, exports "
Leena Miettinen's avatar
Leena Miettinen committed
214
                              "and exportMetaObjectRevisions script bindings."));
215
216
            }
        } else {
Leena Miettinen's avatar
Leena Miettinen committed
217
            addWarning(member->firstSourceLocation(), tr("Expected only script bindings and object definitions."));
218
219
220
221
        }
    }

    if (fmo->className().isEmpty()) {
Leena Miettinen's avatar
Leena Miettinen committed
222
        addError(ast->firstSourceLocation(), tr("Component definition is missing a name binding."));
223
224
225
        return;
    }

226
    // ### add implicit export into the package of c++ types
227
    fmo->addExport(fmo->className(), QmlJS::CppQmlTypes::cppPackage, ComponentVersion());
228
    fmo->updateFingerprint();
229
230
231
    _objects->insert(fmo->className(), fmo);
}

232
233
234
235
236
237
238
239
240
241
void TypeDescriptionReader::readModuleApi(UiObjectDefinition *ast)
{
    ModuleApiInfo apiInfo;

    for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
        UiObjectMember *member = it->member;
        UiScriptBinding *script = dynamic_cast<UiScriptBinding *>(member);

        if (script) {
            const QString name = toString(script->qualifiedId);
242
            if (name == QLatin1String("uri")) {
243
                apiInfo.uri = readStringBinding(script);
244
            } else if (name == QLatin1String("version")) {
245
                apiInfo.version = readNumericVersionBinding(script);
246
            } else if (name == QLatin1String("name")) {
Christian Kamm's avatar
Christian Kamm committed
247
                apiInfo.cppName = readStringBinding(script);
248
249
            } else {
                addWarning(script->firstSourceLocation(),
Leena Miettinen's avatar
Leena Miettinen committed
250
                           tr("Expected only uri, version and name script bindings."));
251
252
            }
        } else {
Leena Miettinen's avatar
Leena Miettinen committed
253
            addWarning(member->firstSourceLocation(), tr("Expected only script bindings."));
254
255
256
257
        }
    }

    if (!apiInfo.version.isValid()) {
Leena Miettinen's avatar
Leena Miettinen committed
258
        addError(ast->firstSourceLocation(), tr("ModuleApi definition has no or invalid version binding."));
259
260
261
262
263
264
265
        return;
    }

    if (_moduleApis)
        _moduleApis->append(apiInfo);
}

266
267
268
269
270
271
272
273
274
275
276
277
278
279
void TypeDescriptionReader::readSignalOrMethod(UiObjectDefinition *ast, bool isMethod, FakeMetaObject::Ptr fmo)
{
    FakeMetaMethod fmm;
    // ### confusion between Method and Slot. Method should be removed.
    if (isMethod)
        fmm.setMethodType(FakeMetaMethod::Slot);
    else
        fmm.setMethodType(FakeMetaMethod::Signal);

    for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
        UiObjectMember *member = it->member;
        UiObjectDefinition *component = dynamic_cast<UiObjectDefinition *>(member);
        UiScriptBinding *script = dynamic_cast<UiScriptBinding *>(member);
        if (component) {
280
            QString name = toString(component->qualifiedTypeNameId);
281
            if (name == QLatin1String("Parameter"))
282
                readParameter(component, &fmm);
283
            else
Leena Miettinen's avatar
Leena Miettinen committed
284
                addWarning(component->firstSourceLocation(), tr("Expected only Parameter object definitions."));
285
        } else if (script) {
286
            QString name = toString(script->qualifiedId);
287
            if (name == QLatin1String("name"))
288
                fmm.setMethodName(readStringBinding(script));
289
            else if (name == QLatin1String("type"))
290
                fmm.setReturnType(readStringBinding(script));
291
            else if (name == QLatin1String("revision"))
292
                fmm.setRevision(readIntBinding(script));
293
            else
Leena Miettinen's avatar
Leena Miettinen committed
294
                addWarning(script->firstSourceLocation(), tr("Expected only name and type script bindings."));
295
296

        } else {
Leena Miettinen's avatar
Leena Miettinen committed
297
            addWarning(member->firstSourceLocation(), tr("Expected only script bindings and object definitions."));
298
299
300
301
        }
    }

    if (fmm.methodName().isEmpty()) {
Leena Miettinen's avatar
Leena Miettinen committed
302
        addError(ast->firstSourceLocation(), tr("Method or signal is missing a name script binding."));
303
304
305
306
307
308
309
310
311
312
313
314
315
        return;
    }

    fmo->addMethod(fmm);
}

void TypeDescriptionReader::readProperty(UiObjectDefinition *ast, FakeMetaObject::Ptr fmo)
{
    QString name;
    QString type;
    bool isPointer = false;
    bool isReadonly = false;
    bool isList = false;
316
    int revision = 0;
317
318
319
320
321

    for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
        UiObjectMember *member = it->member;
        UiScriptBinding *script = dynamic_cast<UiScriptBinding *>(member);
        if (!script) {
Leena Miettinen's avatar
Leena Miettinen committed
322
            addWarning(member->firstSourceLocation(), tr("Expected script binding."));
323
            continue;
324
325
        }

326
        QString id = toString(script->qualifiedId);
327
        if (id == QLatin1String("name"))
328
            name = readStringBinding(script);
329
        else if (id == QLatin1String("type"))
330
            type = readStringBinding(script);
331
        else if (id == QLatin1String("isPointer"))
332
            isPointer = readBoolBinding(script);
333
        else if (id == QLatin1String("isReadonly"))
334
            isReadonly = readBoolBinding(script);
335
        else if (id == QLatin1String("isList"))
336
            isList = readBoolBinding(script);
337
        else if (id == QLatin1String("revision"))
338
            revision = readIntBinding(script);
339
        else
Leena Miettinen's avatar
Leena Miettinen committed
340
            addWarning(script->firstSourceLocation(), tr("Expected only type, name, revision, isPointer, isReadonly and isList script bindings."));
341
342
343
    }

    if (name.isEmpty() || type.isEmpty()) {
Leena Miettinen's avatar
Leena Miettinen committed
344
        addError(ast->firstSourceLocation(), tr("Property object is missing a name or type script binding."));
345
346
347
        return;
    }

348
    fmo->addProperty(FakeMetaProperty(name, type, isList, !isReadonly, isPointer, revision));
349
350
351
352
353
354
355
356
357
358
}

void TypeDescriptionReader::readEnum(UiObjectDefinition *ast, FakeMetaObject::Ptr fmo)
{
    FakeMetaEnum fme;

    for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
        UiObjectMember *member = it->member;
        UiScriptBinding *script = dynamic_cast<UiScriptBinding *>(member);
        if (!script) {
Leena Miettinen's avatar
Leena Miettinen committed
359
            addWarning(member->firstSourceLocation(), tr("Expected script binding."));
360
            continue;
361
362
        }

363
        QString name = toString(script->qualifiedId);
364
        if (name == QLatin1String("name"))
365
            fme.setName(readStringBinding(script));
366
        else if (name == QLatin1String("values"))
367
            readEnumValues(script, &fme);
368
        else
Fawzi Mohamed's avatar
Fawzi Mohamed committed
369
            addWarning(script->firstSourceLocation(), tr("Expected only name and values script bindings."));
370
371
372
373
374
375
376
377
378
379
380
381
382
383
    }

    fmo->addEnum(fme);
}

void TypeDescriptionReader::readParameter(UiObjectDefinition *ast, FakeMetaMethod *fmm)
{
    QString name;
    QString type;

    for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
        UiObjectMember *member = it->member;
        UiScriptBinding *script = dynamic_cast<UiScriptBinding *>(member);
        if (!script) {
Leena Miettinen's avatar
Leena Miettinen committed
384
            addWarning(member->firstSourceLocation(), tr("Expected script binding."));
385
            continue;
386
387
        }

388
        const QString id = toString(script->qualifiedId);
389
        if (id == QLatin1String("name")) {
390
            name = readStringBinding(script);
391
        } else if (id == QLatin1String("type")) {
392
            type = readStringBinding(script);
393
        } else if (id == QLatin1String("isPointer")) {
394
            // ### unhandled
395
        } else if (id == QLatin1String("isReadonly")) {
396
            // ### unhandled
397
        } else if (id == QLatin1String("isList")) {
398
399
            // ### unhandled
        } else {
Leena Miettinen's avatar
Leena Miettinen committed
400
            addWarning(script->firstSourceLocation(), tr("Expected only name and type script bindings."));
401
402
403
404
405
406
407
408
409
        }
    }

    fmm->addParameter(name, type);
}

QString TypeDescriptionReader::readStringBinding(UiScriptBinding *ast)
{
    if (!ast || !ast->statement) {
Leena Miettinen's avatar
Leena Miettinen committed
410
        addError(ast->colonToken, tr("Expected string after colon."));
411
412
413
414
415
        return QString();
    }

    ExpressionStatement *expStmt = dynamic_cast<ExpressionStatement *>(ast->statement);
    if (!expStmt) {
Leena Miettinen's avatar
Leena Miettinen committed
416
        addError(ast->statement->firstSourceLocation(), tr("Expected string after colon."));
417
418
419
420
421
        return QString();
    }

    StringLiteral *stringLit = dynamic_cast<StringLiteral *>(expStmt->expression);
    if (!stringLit) {
Leena Miettinen's avatar
Leena Miettinen committed
422
        addError(expStmt->firstSourceLocation(), tr("Expected string after colon."));
423
424
425
        return QString();
    }

426
    return stringLit->value.toString();
427
428
429
430
431
}

bool TypeDescriptionReader::readBoolBinding(AST::UiScriptBinding *ast)
{
    if (!ast || !ast->statement) {
Leena Miettinen's avatar
Leena Miettinen committed
432
        addError(ast->colonToken, tr("Expected boolean after colon."));
433
434
435
436
437
        return false;
    }

    ExpressionStatement *expStmt = dynamic_cast<ExpressionStatement *>(ast->statement);
    if (!expStmt) {
Leena Miettinen's avatar
Leena Miettinen committed
438
        addError(ast->statement->firstSourceLocation(), tr("Expected boolean after colon."));
439
440
441
442
443
444
        return false;
    }

    TrueLiteral *trueLit = dynamic_cast<TrueLiteral *>(expStmt->expression);
    FalseLiteral *falseLit = dynamic_cast<FalseLiteral *>(expStmt->expression);
    if (!trueLit && !falseLit) {
Leena Miettinen's avatar
Leena Miettinen committed
445
        addError(expStmt->firstSourceLocation(), tr("Expected true or false after colon."));
446
447
448
449
450
451
        return false;
    }

    return trueLit;
}

452
453
454
double TypeDescriptionReader::readNumericBinding(AST::UiScriptBinding *ast)
{
    if (!ast || !ast->statement) {
Leena Miettinen's avatar
Leena Miettinen committed
455
        addError(ast->colonToken, tr("Expected numeric literal after colon."));
456
457
458
459
460
        return 0;
    }

    ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
    if (!expStmt) {
Leena Miettinen's avatar
Leena Miettinen committed
461
        addError(ast->statement->firstSourceLocation(), tr("Expected numeric literal after colon."));
462
463
464
465
466
        return 0;
    }

    NumericLiteral *numericLit = AST::cast<NumericLiteral *>(expStmt->expression);
    if (!numericLit) {
Leena Miettinen's avatar
Leena Miettinen committed
467
        addError(expStmt->firstSourceLocation(), tr("Expected numeric literal after colon."));
468
469
470
471
472
473
        return 0;
    }

    return numericLit->value;
}

474
475
476
477
478
ComponentVersion TypeDescriptionReader::readNumericVersionBinding(UiScriptBinding *ast)
{
    ComponentVersion invalidVersion;

    if (!ast || !ast->statement) {
Leena Miettinen's avatar
Leena Miettinen committed
479
        addError(ast->colonToken, tr("Expected numeric literal after colon."));
480
481
482
483
484
        return invalidVersion;
    }

    ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
    if (!expStmt) {
Leena Miettinen's avatar
Leena Miettinen committed
485
        addError(ast->statement->firstSourceLocation(), tr("Expected numeric literal after colon."));
486
487
488
489
490
        return invalidVersion;
    }

    NumericLiteral *numericLit = AST::cast<NumericLiteral *>(expStmt->expression);
    if (!numericLit) {
Leena Miettinen's avatar
Leena Miettinen committed
491
        addError(expStmt->firstSourceLocation(), tr("Expected numeric literal after colon."));
492
493
494
495
496
497
        return invalidVersion;
    }

    return ComponentVersion(_source.mid(numericLit->literalToken.begin(), numericLit->literalToken.length));
}

498
499
500
int TypeDescriptionReader::readIntBinding(AST::UiScriptBinding *ast)
{
    double v = readNumericBinding(ast);
Christian Kamm's avatar
Christian Kamm committed
501
    int i = static_cast<int>(v);
502
503

    if (i != v) {
Leena Miettinen's avatar
Leena Miettinen committed
504
        addError(ast->firstSourceLocation(), tr("Expected integer after colon."));
505
506
507
508
509
510
        return 0;
    }

    return i;
}

511
512
513
void TypeDescriptionReader::readExports(UiScriptBinding *ast, FakeMetaObject::Ptr fmo)
{
    if (!ast || !ast->statement) {
Leena Miettinen's avatar
Leena Miettinen committed
514
        addError(ast->colonToken, tr("Expected array of strings after colon."));
515
516
517
518
519
        return;
    }

    ExpressionStatement *expStmt = dynamic_cast<ExpressionStatement *>(ast->statement);
    if (!expStmt) {
Leena Miettinen's avatar
Leena Miettinen committed
520
        addError(ast->statement->firstSourceLocation(), tr("Expected array of strings after colon."));
521
522
523
524
525
        return;
    }

    ArrayLiteral *arrayLit = dynamic_cast<ArrayLiteral *>(expStmt->expression);
    if (!arrayLit) {
Leena Miettinen's avatar
Leena Miettinen committed
526
        addError(expStmt->firstSourceLocation(), tr("Expected array of strings after colon."));
527
528
529
530
531
532
        return;
    }

    for (ElementList *it = arrayLit->elements; it; it = it->next) {
        StringLiteral *stringLit = dynamic_cast<StringLiteral *>(it->expression);
        if (!stringLit) {
Leena Miettinen's avatar
Leena Miettinen committed
533
            addError(arrayLit->firstSourceLocation(), tr("Expected array literal with only string literal members."));
534
535
            return;
        }
536
        QString exp = stringLit->value.toString();
537
538
539
540
541
        int slashIdx = exp.indexOf(QLatin1Char('/'));
        int spaceIdx = exp.indexOf(QLatin1Char(' '));
        ComponentVersion version(exp.mid(spaceIdx + 1));

        if (spaceIdx == -1 || !version.isValid()) {
Leena Miettinen's avatar
Leena Miettinen committed
542
            addError(stringLit->firstSourceLocation(), tr("Expected string literal to contain 'Package/Name major.minor' or 'Name major.minor'."));
543
544
545
546
547
548
549
550
551
552
553
554
            continue;
        }
        QString package;
        if (slashIdx != -1)
            package = exp.left(slashIdx);
        QString name = exp.mid(slashIdx + 1, spaceIdx - (slashIdx+1));

        // ### relocatable exports where package is empty?
        fmo->addExport(name, package, version);
    }
}

555
556
557
void TypeDescriptionReader::readMetaObjectRevisions(UiScriptBinding *ast, FakeMetaObject::Ptr fmo)
{
    if (!ast || !ast->statement) {
Leena Miettinen's avatar
Leena Miettinen committed
558
        addError(ast->colonToken, tr("Expected array of numbers after colon."));
559
560
561
562
563
        return;
    }

    ExpressionStatement *expStmt = dynamic_cast<ExpressionStatement *>(ast->statement);
    if (!expStmt) {
Leena Miettinen's avatar
Leena Miettinen committed
564
        addError(ast->statement->firstSourceLocation(), tr("Expected array of numbers after colon."));
565
566
567
568
569
        return;
    }

    ArrayLiteral *arrayLit = dynamic_cast<ArrayLiteral *>(expStmt->expression);
    if (!arrayLit) {
Leena Miettinen's avatar
Leena Miettinen committed
570
        addError(expStmt->firstSourceLocation(), tr("Expected array of numbers after colon."));
571
572
573
574
575
576
577
578
        return;
    }

    int exportIndex = 0;
    const int exportCount = fmo->exports().size();
    for (ElementList *it = arrayLit->elements; it; it = it->next, ++exportIndex) {
        NumericLiteral *numberLit = cast<NumericLiteral *>(it->expression);
        if (!numberLit) {
Leena Miettinen's avatar
Leena Miettinen committed
579
            addError(arrayLit->firstSourceLocation(), tr("Expected array literal with only number literal members."));
580
581
582
583
            return;
        }

        if (exportIndex >= exportCount) {
Leena Miettinen's avatar
Leena Miettinen committed
584
            addError(numberLit->firstSourceLocation(), tr("Meta object revision without matching export."));
585
586
587
588
589
590
            return;
        }

        const double v = numberLit->value;
        const int metaObjectRevision = static_cast<int>(v);
        if (metaObjectRevision != v) {
Leena Miettinen's avatar
Leena Miettinen committed
591
            addError(numberLit->firstSourceLocation(), tr("Expected integer."));
592
593
594
595
596
597
598
            return;
        }

        fmo->setExportMetaObjectRevision(exportIndex, metaObjectRevision);
    }
}

599
600
601
void TypeDescriptionReader::readEnumValues(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaEnum *fme)
{
    if (!ast || !ast->statement) {
Leena Miettinen's avatar
Leena Miettinen committed
602
        addError(ast->colonToken, tr("Expected object literal after colon."));
603
604
605
606
607
        return;
    }

    ExpressionStatement *expStmt = dynamic_cast<ExpressionStatement *>(ast->statement);
    if (!expStmt) {
Leena Miettinen's avatar
Leena Miettinen committed
608
        addError(ast->statement->firstSourceLocation(), tr("Expected object literal after colon."));
609
610
611
612
613
        return;
    }

    ObjectLiteral *objectLit = dynamic_cast<ObjectLiteral *>(expStmt->expression);
    if (!objectLit) {
Leena Miettinen's avatar
Leena Miettinen committed
614
        addError(expStmt->firstSourceLocation(), tr("Expected object literal after colon."));
615
616
617
        return;
    }

Fawzi Mohamed's avatar
Fawzi Mohamed committed
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
    for (PropertyAssignmentList *it = objectLit->properties; it; it = it->next) {
        PropertyNameAndValue *assignement = AST::cast<PropertyNameAndValue *>(it->assignment);
        if (assignement) {
            StringLiteralPropertyName *propName = dynamic_cast<StringLiteralPropertyName *>(assignement->name);
            NumericLiteral *value = dynamic_cast<NumericLiteral *>(assignement->value);
            UnaryMinusExpression *minus = dynamic_cast<UnaryMinusExpression *>(assignement->value);
            if (minus)
                value = dynamic_cast<NumericLiteral *>(minus->expression);
            if (!propName || !value) {
                addError(objectLit->firstSourceLocation(), tr("Expected object literal to contain only 'string: number' elements."));
                continue;
            }

            double v = value->value;
            if (minus)
                v = -v;
            fme->addKey(propName->id.toString(), v);
635
636
            continue;
        }
Fawzi Mohamed's avatar
Fawzi Mohamed committed
637
        PropertyGetterSetter *getterSetter = AST::cast<PropertyGetterSetter *>(it->assignment);
Orgad Shaneh's avatar
Orgad Shaneh committed
638
        if (getterSetter)
Fawzi Mohamed's avatar
Fawzi Mohamed committed
639
            addError(objectLit->firstSourceLocation(), tr("Enum should not contain getter and setters, but only 'string: number' elements."));
640
641
    }
}