qmljsinterpreter.cpp 85.4 KB
Newer Older
1
2
3
4
/**************************************************************************
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
5
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "qmljsinterpreter.h"
31
#include "qmljsevaluate.h"
32
#include "qmljslink.h"
33
#include "qmljsbind.h"
34
#include "qmljsscopebuilder.h"
35
#include "qmljscomponentversion.h"
36
#include "parser/qmljsast_p.h"
37
38

#include <QtCore/QFile>
39
#include <QtCore/QDir>
40
41
#include <QtCore/QString>
#include <QtCore/QStringList>
42
43
#include <QtCore/QMetaObject>
#include <QtCore/QMetaProperty>
44
#include <QtCore/QXmlStreamReader>
45
#include <QtCore/QProcess>
46
47
48
#include <QtCore/QDebug>

using namespace QmlJS::Interpreter;
49
using namespace QmlJS::AST;
50

Roberto Raggi's avatar
Roberto Raggi committed
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
namespace {

class LookupMember: public MemberProcessor
{
    QString _name;
    const Value *_value;

    bool process(const QString &name, const Value *value)
    {
        if (_value)
            return false;

        if (name == _name) {
            _value = value;
            return false;
        }

        return true;
    }

public:
    LookupMember(const QString &name)
        : _name(name), _value(0) {}

    const Value *value() const { return _value; }

    virtual bool processProperty(const QString &name, const Value *value)
    {
        return process(name, value);
    }

    virtual bool processEnumerator(const QString &name, const Value *value)
    {
        return process(name, value);
    }

    virtual bool processSignal(const QString &name, const Value *value)
    {
        return process(name, value);
    }

    virtual bool processSlot(const QString &name, const Value *value)
    {
        return process(name, value);
    }

    virtual bool processGeneratedSlot(const QString &name, const Value *value)
    {
        return process(name, value);
    }
};

} // end of anonymous namespace

105
106
107
108
namespace QmlJS {
namespace Interpreter {

class FakeMetaEnum {
Erik Verbruggen's avatar
Erik Verbruggen committed
109
110
111
    QString m_name;
    QStringList m_keys;
    QList<int> m_values;
112
113
114

public:
    FakeMetaEnum(const QString &name)
Erik Verbruggen's avatar
Erik Verbruggen committed
115
        : m_name(name)
116
117
    {}

118
119
120
    QString name() const
    { return m_name; }

121
    void addKey(const QString &key, int value)
Erik Verbruggen's avatar
Erik Verbruggen committed
122
    { m_keys.append(key); m_values.append(value); }
123
124

    QString key(int index) const
Erik Verbruggen's avatar
Erik Verbruggen committed
125
    { return m_keys.at(index); }
126
127

    int keyCount() const
Erik Verbruggen's avatar
Erik Verbruggen committed
128
    { return m_keys.size(); }
Christian Kamm's avatar
Christian Kamm committed
129
130
131

    QStringList keys() const
    { return m_keys; }
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
};

class FakeMetaMethod {
public:
    enum {
        Signal,
        Slot,
        Method
    };

    enum {
        Private,
        Protected,
        Public
    };

public:
    FakeMetaMethod(const QString &name, const QString &returnType = QString())
150
        : m_name(name), m_returnType(returnType), m_methodTy(Method), m_methodAccess(Public)
151
152
153
    {}

    QString methodName() const
Erik Verbruggen's avatar
Erik Verbruggen committed
154
    { return m_name; }
155
156

    QStringList parameterNames() const
Erik Verbruggen's avatar
Erik Verbruggen committed
157
    { return m_paramNames; }
158
159

    QStringList parameterTypes() const
Erik Verbruggen's avatar
Erik Verbruggen committed
160
    { return m_paramTypes; }
161
162

    void addParameter(const QString &name, const QString &type)
Erik Verbruggen's avatar
Erik Verbruggen committed
163
    { m_paramNames.append(name); m_paramTypes.append(type); }
164
165

    int methodType() const
Erik Verbruggen's avatar
Erik Verbruggen committed
166
    { return m_methodTy; }
167
    void setMethodType(int methodType)
Erik Verbruggen's avatar
Erik Verbruggen committed
168
    { m_methodTy = methodType; }
169
170

    int access() const
Erik Verbruggen's avatar
Erik Verbruggen committed
171
    { return m_methodAccess; }
172
173

private:
Erik Verbruggen's avatar
Erik Verbruggen committed
174
175
176
177
178
179
    QString m_name;
    QString m_returnType;
    QStringList m_paramNames;
    QStringList m_paramTypes;
    int m_methodTy;
    int m_methodAccess;
180
181
182
};

class FakeMetaProperty {
Erik Verbruggen's avatar
Erik Verbruggen committed
183
184
185
    QString m_propertyName;
    QString m_type;
    bool m_isList;
186
187
188

public:
    FakeMetaProperty(const QString &name, const QString &type, bool isList)
Erik Verbruggen's avatar
Erik Verbruggen committed
189
        : m_propertyName(name), m_type(type), m_isList(isList)
190
191
192
    {}

    QString name() const
Erik Verbruggen's avatar
Erik Verbruggen committed
193
    { return m_propertyName; }
194
195

    QString typeName() const
Erik Verbruggen's avatar
Erik Verbruggen committed
196
    { return m_type; }
197
198
199

    bool isList() const
    { return m_isList; }
200
201
202
203
204
205
};

class FakeMetaObject {
    FakeMetaObject(FakeMetaObject&);
    FakeMetaObject &operator=(const FakeMetaObject&);

Erik Verbruggen's avatar
Erik Verbruggen committed
206
207
    QString m_name;
    QString m_package;
208
    QString m_packageNameVersion;
209
    ComponentVersion m_version;
Erik Verbruggen's avatar
Erik Verbruggen committed
210
211
212
    const FakeMetaObject *m_super;
    QString m_superName;
    QList<FakeMetaEnum> m_enums;
213
    QHash<QString, int> m_enumNameToIndex;
Erik Verbruggen's avatar
Erik Verbruggen committed
214
    QList<FakeMetaProperty> m_props;
215
    QHash<QString, int> m_propNameToIdx;
Erik Verbruggen's avatar
Erik Verbruggen committed
216
    QList<FakeMetaMethod> m_methods;
217
    QString m_defaultPropertyName;
218
219

public:
220
221
    FakeMetaObject(const QString &name, const QString &package, ComponentVersion version)
        : m_name(name), m_package(package), m_version(version), m_super(0)
222
223
224
225
226
    {
        m_packageNameVersion = QString::fromLatin1("%1.%2 %3.%4").arg(
                package, name,
                QString::number(version.majorVersion()), QString::number(version.minorVersion()));
    }
227
228

    void setSuperclassName(const QString &superclass)
Erik Verbruggen's avatar
Erik Verbruggen committed
229
    { m_superName = superclass; }
230
    QString superclassName() const
Erik Verbruggen's avatar
Erik Verbruggen committed
231
    { return m_superName; }
232
233

    void setSuperclass(FakeMetaObject *superClass)
Erik Verbruggen's avatar
Erik Verbruggen committed
234
    { m_super = superClass; }
235
    const FakeMetaObject *superClass() const
Erik Verbruggen's avatar
Erik Verbruggen committed
236
    { return m_super; }
237
    QString className() const
Erik Verbruggen's avatar
Erik Verbruggen committed
238
    { return m_name; }
239
    QString packageName() const
Erik Verbruggen's avatar
Erik Verbruggen committed
240
    { return m_package; }
241
242
    QString packageClassVersionString() const
    { return m_packageNameVersion; }
243
244

    void addEnum(const FakeMetaEnum &fakeEnum)
245
    { m_enumNameToIndex.insert(fakeEnum.name(), m_enums.size()); m_enums.append(fakeEnum); }
246
    int enumeratorCount() const
Erik Verbruggen's avatar
Erik Verbruggen committed
247
    { return m_enums.size(); }
248
249
250
    int enumeratorOffset() const
    { return 0; }
    FakeMetaEnum enumerator(int index) const
Erik Verbruggen's avatar
Erik Verbruggen committed
251
    { return m_enums.at(index); }
252
253
    int enumeratorIndex(const QString &name) const
    { return m_enumNameToIndex.value(name, -1); }
254
255

    void addProperty(const FakeMetaProperty &property)
256
    { m_propNameToIdx.insert(property.name(), m_props.size()); m_props.append(property); }
257
    int propertyCount() const
Erik Verbruggen's avatar
Erik Verbruggen committed
258
    { return m_props.size(); }
259
260
261
    int propertyOffset() const
    { return 0; }
    FakeMetaProperty property(int index) const
Erik Verbruggen's avatar
Erik Verbruggen committed
262
    { return m_props.at(index); }
263
264
    int propertyIndex(const QString &name) const
    { return m_propNameToIdx.value(name, -1); }
265
266

    void addMethod(const FakeMetaMethod &method)
Erik Verbruggen's avatar
Erik Verbruggen committed
267
    { m_methods.append(method); }
268
    int methodCount() const
Erik Verbruggen's avatar
Erik Verbruggen committed
269
    { return m_methods.size(); }
270
271
272
    int methodOffset() const
    { return 0; }
    FakeMetaMethod method(int index) const
Erik Verbruggen's avatar
Erik Verbruggen committed
273
    { return m_methods.at(index); }
274

275
276
    ComponentVersion version() const
    { return m_version; }
277
278
279
280
281
282

    QString defaultPropertyName() const
    { return m_defaultPropertyName; }

    void setDefaultPropertyName(const QString defaultPropertyName)
    { m_defaultPropertyName = defaultPropertyName; }
283
284
285
286
};

} // end of Interpreter namespace
} // end of QmlJS namespace
Roberto Raggi's avatar
Roberto Raggi committed
287

Roberto Raggi's avatar
Roberto Raggi committed
288
289
namespace {

290
291
class MetaFunction: public FunctionValue
{
292
    FakeMetaMethod _method;
293
294

public:
295
    MetaFunction(const FakeMetaMethod &method, Engine *engine)
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
        : FunctionValue(engine), _method(method)
    {
    }

    virtual const Value *returnValue() const
    {
        return engine()->undefinedValue();
    }

    virtual int argumentCount() const
    {
        return _method.parameterNames().size();
    }

    virtual const Value *argument(int) const
    {
        return engine()->undefinedValue();
    }

    virtual QString argumentName(int index) const
    {
        if (index < _method.parameterNames().size())
            return _method.parameterNames().at(index);

        return FunctionValue::argumentName(index);
    }

    virtual bool isVariadic() const
    {
        return false;
    }

    virtual const Value *invoke(const Activation *) const
    {
        return engine()->undefinedValue();
    }
};

334
335
class QmlXmlReader
{
336
337
    Q_DECLARE_TR_FUNCTIONS(QmlJS::Interpreter::QmlXmlReader)

338
339
340
public:
    QmlXmlReader(QIODevice *dev)
        : _xml(dev)
Erik Verbruggen's avatar
Erik Verbruggen committed
341
        , _objects(0)
342
343
    {}

344
345
346
347
    QmlXmlReader(const QByteArray &data)
        : _xml(data)
    {}

348
349
350
351
352
353
354
355
    bool operator()(QMap<QString, FakeMetaObject *> *objects) {
        Q_ASSERT(objects);
        _objects = objects;

        if (_xml.readNextStartElement()) {
            if (_xml.name() == "module")
                readModule();
            else
356
                _xml.raiseError(tr("The file is not module file."));
357
358
359
360
361
362
363
364
365
366
367
        }

        return !_xml.error();
    }

    QString errorMessage() const {
        return _xml.errorString();
    }

private:
    void unexpectedElement(const QStringRef &child, const QString &parent) {
368
        _xml.raiseError(tr("Unexpected element <%1> in <%2>").arg(child.toString(), parent));
369
370
371
372
373
374
375
376
    }

    void ignoreAttr(const QXmlStreamAttribute &attr) {
        qDebug() << "** ignoring attribute" << attr.name().toString()
                 << "in tag" << _xml.name();
    }

    void invalidAttr(const QString &value, const QString &attrName, const QString &tag) {
377
        _xml.raiseError(tr("invalid value '%1' for attribute %2 in <%3>").arg(value, attrName, tag));
378
379
380
    }

    void noValidAttr(const QString &attrName, const QString &tag) {
381
        _xml.raiseError(tr("<%1> has no valid %2 attribute").arg(tag, attrName));
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
    }

    void readModule()
    {
        Q_ASSERT(_xml.isStartElement() && _xml.name() == QLatin1String("module"));

        foreach (const QXmlStreamAttribute &attr, _xml.attributes())
            ignoreAttr(attr);

        while (_xml.readNextStartElement()) {
            if (_xml.name() == QLatin1String("type"))
                readType();
            else
                unexpectedElement(_xml.name(), QLatin1String("module"));
        }
    }

    void readType()
    {
        const QLatin1String tag("type");
        Q_ASSERT(_xml.isStartElement() && _xml.name() == tag);

404
        bool doInsert = true;
405
        QString name, defaultPropertyName;
406
        QmlJS::ComponentVersion version;
407
408
409
410
411
412
413
414
415
        QString extends;
        foreach (const QXmlStreamAttribute &attr, _xml.attributes()) {
            if (attr.name() == QLatin1String("name")) {
                name = attr.value().toString();
                if (name.isEmpty()) {
                    invalidAttr(name, QLatin1String("name"), tag);
                    return;
                }
            } else if (attr.name() == QLatin1String("version")) {
416
417
                QString versionStr = attr.value().toString();
                int dotIdx = versionStr.indexOf('.');
418
419
                if (dotIdx == -1) {
                    bool ok = false;
420
                    const int major = versionStr.toInt(&ok);
421
                    if (!ok) {
422
                        invalidAttr(versionStr, QLatin1String("version"), tag);
423
424
                        return;
                    }
425
                    version = QmlJS::ComponentVersion(major, QmlJS::ComponentVersion::NoVersion);
426
427
                } else {
                    bool ok = false;
428
                    const int major = versionStr.left(dotIdx).toInt(&ok);
429
                    if (!ok) {
430
                        invalidAttr(versionStr, QLatin1String("version"), tag);
431
432
                        return;
                    }
433
                    const int minor = versionStr.mid(dotIdx + 1).toInt(&ok);
434
                    if (!ok) {
435
                        invalidAttr(versionStr, QLatin1String("version"), tag);
436
437
                        return;
                    }
438
                    version = QmlJS::ComponentVersion(major, minor);
439
                }
440
441
            } else if (attr.name() == QLatin1String("defaultProperty")) {
                defaultPropertyName = attr.value().toString();
442
443
444
            } else if (attr.name() == QLatin1String("extends")) {
                if (! attr.value().isEmpty())
                    extends = attr.value().toString();
445
446
447
448
449

                if (extends == name) {
                    invalidAttr(extends, QLatin1String("extends"), tag);
                    doInsert = false;
                }
450
451
452
453
454
455
456
            } else {
                ignoreAttr(attr);
            }
        }

        QString className, packageName;
        split(name, &packageName, &className);
457
        FakeMetaObject *metaObject = new FakeMetaObject(className, packageName, version);
458
459
        if (! extends.isEmpty())
            metaObject->setSuperclassName(extends);
460
461
        if (! defaultPropertyName.isEmpty())
            metaObject->setDefaultPropertyName(defaultPropertyName);
462
463
464
465
466
467
468
469
470
471
472
473
474
475

        while (_xml.readNextStartElement()) {
            if (_xml.name() == QLatin1String("property"))
                readProperty(metaObject);
            else if (_xml.name() == QLatin1String("enum"))
                readEnum(metaObject);
            else if (_xml.name() == QLatin1String("signal"))
                readSignal(metaObject);
            else if (_xml.name() == QLatin1String("method"))
                readMethod(metaObject);
            else
                unexpectedElement(_xml.name(), tag);
        }

476
477
478
479
        if (doInsert)
            _objects->insert(name, metaObject);
        else
            delete metaObject;
480
481
482
    }

    bool split(const QString &name, QString *packageName, QString *className) {
483
        int dotIdx = name.lastIndexOf(QLatin1Char('.'));
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
        if (dotIdx != -1) {
            if (packageName)
                *packageName = name.left(dotIdx);
            if (className)
                *className = name.mid(dotIdx + 1);
            return true;
        } else {
            if (packageName)
                packageName->clear();
            if (className)
                *className = name;
            return false;
        }
    }

    void readProperty(FakeMetaObject *metaObject)
    {
        const QLatin1String tag("property");
        Q_ASSERT(_xml.isStartElement() && _xml.name() == tag);

        QString name, type;
        bool isList = false;
        foreach (const QXmlStreamAttribute &attr, _xml.attributes()) {
            if (attr.name() == QLatin1String("name")) {
                name = attr.value().toString();
            } else if (attr.name() == QLatin1String("type")) {
                type = attr.value().toString();
            } else if (attr.name() == QLatin1String("isList")) {
                if (attr.value() == QLatin1String("true")) {
                    isList = true;
                } else if (attr.value() == QLatin1String("false")) {
                    isList = false;
                } else {
                    invalidAttr(attr.value().toString(), QLatin1String("idList"), tag);
                    return;
                }
            } else {
                ignoreAttr(attr);
            }
        }

        if (name.isEmpty())
            noValidAttr(QLatin1String("name"), tag);
        else if (type.isEmpty())
            noValidAttr(QLatin1String("type"), tag);
        else
            createProperty(metaObject, name, type, isList);

        while (_xml.readNextStartElement()) {
            unexpectedElement(_xml.name(), tag);
        }
    }

    void createProperty(FakeMetaObject *metaObject, const QString &name,
                        const QString &type, bool isList) {
        Q_ASSERT(metaObject);

        metaObject->addProperty(FakeMetaProperty(name, type, isList));
    }

    void readEnum(FakeMetaObject *metaObject)
    {
        Q_ASSERT(metaObject);

        QLatin1String tag("enum");
        Q_ASSERT(_xml.isStartElement() && _xml.name() == tag);

        QString name;
        foreach (const QXmlStreamAttribute &attr, _xml.attributes()) {
            if (attr.name() == QLatin1String("name")) {
                name = attr.value().toString();
            } else {
                ignoreAttr(attr);
            }
        }

        if (name.isEmpty()) {
            noValidAttr(QLatin1String("name"), tag);
            return;
        }

        FakeMetaEnum metaEnum(name);

        while (_xml.readNextStartElement()) {
            if (_xml.name() == QLatin1String("enumerator"))
                readEnumerator(&metaEnum);
            else
                unexpectedElement(_xml.name(), tag);
        }
573
574

        metaObject->addEnum(metaEnum);
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
    }

    void readEnumerator(FakeMetaEnum *metaEnum)
    {
        Q_ASSERT(metaEnum);

        QLatin1String tag("enumerator");
        Q_ASSERT(_xml.isStartElement() && _xml.name() == tag);

        QString name;
        int value = 0;
        foreach (const QXmlStreamAttribute &attr, _xml.attributes()) {
            if (attr.name() == QLatin1String("name")) {
                name = attr.value().toString();
            } else if (attr.name() == QLatin1String("value")) {
                const QString valueStr = attr.value().toString();
                bool ok = false;
                value = valueStr.toInt(&ok);
                if (!ok) {
                    invalidAttr(valueStr, QLatin1String("value"), tag);
                }
            } else {
                ignoreAttr(attr);
            }
        }

        if (name.isEmpty())
            noValidAttr(QLatin1String("name"), tag);
        else
            metaEnum->addKey(name, value);

        while (_xml.readNextStartElement()) {
            unexpectedElement(_xml.name(), tag);
        }
    }

    void readSignal(FakeMetaObject *metaObject)
    {
        Q_ASSERT(metaObject);
        QLatin1String tag("signal");
        Q_ASSERT(_xml.isStartElement() && _xml.name() == tag);

        QString name;
        foreach (const QXmlStreamAttribute &attr, _xml.attributes()) {
            if (attr.name() == QLatin1String("name")) {
                name = attr.value().toString();
            } else {
                ignoreAttr(attr);
            }
        }

        if (name.isEmpty()) {
            noValidAttr(QLatin1String("name"), tag);
            return;
        }

        FakeMetaMethod method(name);
        method.setMethodType(FakeMetaMethod::Signal);

        while (_xml.readNextStartElement()) {
            if (_xml.name() == QLatin1String("param")) {
                readParam(&method);
            } else {
                unexpectedElement(_xml.name(), tag);
            }
        }
641
642

        metaObject->addMethod(method);
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
    }

    void readParam(FakeMetaMethod *method)
    {
        Q_ASSERT(method);
        QLatin1String tag("param");
        Q_ASSERT(_xml.isStartElement() && _xml.name() == tag);

        QString name, type;
        foreach (const QXmlStreamAttribute &attr, _xml.attributes()) {
            if (attr.name() == QLatin1String("name")) {
                name = attr.value().toString();
            } else if (attr.name() == QLatin1String("type")) {
                type = attr.value().toString();
            } else {
                ignoreAttr(attr);
            }
        }

        // note: name attribute is optional
        if (type.isEmpty())
            noValidAttr(QLatin1String("type"), tag);

        method->addParameter(name, type);

        while (_xml.readNextStartElement()) {
            unexpectedElement(_xml.name(), tag);
        }
    }

    void readMethod(FakeMetaObject *metaObject)
    {
        Q_ASSERT(metaObject);
        QLatin1String tag("method");
        Q_ASSERT(_xml.isStartElement() && _xml.name() == tag);

        QString name, type;
        foreach (const QXmlStreamAttribute &attr, _xml.attributes()) {
            if (attr.name() == QLatin1String("name")) {
                name = attr.value().toString();
            } else if (attr.name() == QLatin1String("type")) {
                type = attr.value().toString();
            } else {
                ignoreAttr(attr);
            }
        }

        // note: type attribute is optional, in which case it's a void method.
        if (name.isEmpty()) {
            noValidAttr(QLatin1String("name"), tag);
            return;
        }

        FakeMetaMethod method(name, type);
697
        method.setMethodType(FakeMetaMethod::Slot);
698
699
700
701
702
703
704
705

        while (_xml.readNextStartElement()) {
            if (_xml.name() == QLatin1String("param")) {
                readParam(&method);
            } else {
                unexpectedElement(_xml.name(), tag);
            }
        }
706
707

        metaObject->addMethod(method);
708
709
710
711
712
713
714
    }

private:
    QXmlStreamReader _xml;
    QMap<QString, FakeMetaObject *> *_objects;
};

Roberto Raggi's avatar
Roberto Raggi committed
715
716
} // end of anonymous namespace

717
QmlObjectValue::QmlObjectValue(const FakeMetaObject *metaObject, Engine *engine)
718
    : ObjectValue(engine),
719
      _metaObject(metaObject)
720
{
721
    setClassName(metaObject->className()); // ### TODO: we probably need to do more than just this...
722
}
Roberto Raggi's avatar
Roberto Raggi committed
723

724
725
QmlObjectValue::~QmlObjectValue()
{}
Roberto Raggi's avatar
Roberto Raggi committed
726

727
const Value *QmlObjectValue::findOrCreateSignature(int index, const FakeMetaMethod &method, QString *methodName) const
Roberto Raggi's avatar
Roberto Raggi committed
728
{
729
    *methodName = method.methodName();
Roberto Raggi's avatar
Roberto Raggi committed
730
731
732
733
    const Value *value = _metaSignature.value(index);
    if (! value) {
        value = new MetaFunction(method, engine());
        _metaSignature.insert(index, value);
Roberto Raggi's avatar
Roberto Raggi committed
734
    }
Roberto Raggi's avatar
Roberto Raggi committed
735
    return value;
736
}
Roberto Raggi's avatar
Roberto Raggi committed
737

738
739
void QmlObjectValue::processMembers(MemberProcessor *processor) const
{
Roberto Raggi's avatar
Roberto Raggi committed
740
    // process the meta enums
741
742
    for (int index = _metaObject->enumeratorOffset(); index < _metaObject->enumeratorCount(); ++index) {
        FakeMetaEnum e = _metaObject->enumerator(index);
743
744

        for (int i = 0; i < e.keyCount(); ++i) {
745
            processor->processEnumerator(e.key(i), engine()->numberValue());
746
747
748
        }
    }

Roberto Raggi's avatar
Roberto Raggi committed
749
750
    // process the meta properties
    for (int index = 0; index < _metaObject->propertyCount(); ++index) {
751
        FakeMetaProperty prop = _metaObject->property(index);
752

Roberto Raggi's avatar
Roberto Raggi committed
753
754
        processor->processProperty(prop.name(), propertyValue(prop));
    }
755

Roberto Raggi's avatar
Roberto Raggi committed
756
757
    // process the meta methods
    for (int index = 0; index < _metaObject->methodCount(); ++index) {
758
        FakeMetaMethod method = _metaObject->method(index);
Roberto Raggi's avatar
Roberto Raggi committed
759
760
        QString methodName;
        const Value *signature = findOrCreateSignature(index, method, &methodName);
761

762
        if (method.methodType() == FakeMetaMethod::Slot && method.access() == FakeMetaMethod::Public) {
Roberto Raggi's avatar
Roberto Raggi committed
763
            processor->processSlot(methodName, signature);
764

765
        } else if (method.methodType() == FakeMetaMethod::Signal && method.access() != FakeMetaMethod::Private) {
766
            // process the signal
Roberto Raggi's avatar
Roberto Raggi committed
767
            processor->processSignal(methodName, signature);
768

769
770
771
772
            QString slotName;
            slotName += QLatin1String("on");
            slotName += methodName.at(0).toUpper();
            slotName += methodName.midRef(1);
773

774
            // process the generated slot
Roberto Raggi's avatar
Roberto Raggi committed
775
            processor->processGeneratedSlot(slotName, signature);
776
        }
Roberto Raggi's avatar
Roberto Raggi committed
777
778
    }

779
780
781
    ObjectValue::processMembers(processor);
}

782
const Value *QmlObjectValue::propertyValue(const FakeMetaProperty &prop) const
783
{
784
    const QString typeName = prop.typeName();
Roberto Raggi's avatar
Roberto Raggi committed
785

786
    // ### Verify type resolving.
787
    QmlObjectValue *objectValue = engine()->cppQmlTypes().typeForImport(typeName);
788
789
    if (objectValue)
        return objectValue;
Roberto Raggi's avatar
Roberto Raggi committed
790

791
    const Value *value = engine()->undefinedValue();
792
793
794
795
    if (typeName == QLatin1String("QByteArray")
            || typeName == QLatin1String("string")
            || typeName == QLatin1String("QString")
            || typeName == QLatin1String("QUrl")) {
796
        value = engine()->stringValue();
797
    } else if (typeName == QLatin1String("bool")) {
798
        value = engine()->booleanValue();
799
800
801
802
803
804
805
    } else if (typeName == QLatin1String("int")
            || typeName == QLatin1String("float")
            || typeName == QLatin1String("double")
            || typeName == QLatin1String("qreal")
            || typeName == QLatin1String("long")
            // ### Review: more types here?
            ) {
806
        value = engine()->numberValue();
807
    } else if (typeName == QLatin1String("QFont")) {
808
        ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
809
        object->setClassName(QLatin1String("Font"));
810
811
        object->setProperty("family", engine()->stringValue());
        object->setProperty("weight", engine()->undefinedValue()); // ### make me an object
Yann Bodson's avatar
Yann Bodson committed
812
        object->setProperty("capitalization", engine()->undefinedValue()); // ### make me an object
813
814
815
816
817
818
819
820
821
822
        object->setProperty("bold", engine()->booleanValue());
        object->setProperty("italic", engine()->booleanValue());
        object->setProperty("underline", engine()->booleanValue());
        object->setProperty("overline", engine()->booleanValue());
        object->setProperty("strikeout", engine()->booleanValue());
        object->setProperty("pointSize", engine()->numberValue());
        object->setProperty("pixelSize", engine()->numberValue());
        object->setProperty("letterSpacing", engine()->numberValue());
        object->setProperty("wordSpacing", engine()->numberValue());
        value = object;
823
824
825
    } else if (typeName == QLatin1String("QPoint")
            || typeName == QLatin1String("QPointF")
            || typeName == QLatin1String("QVector2D")) {
826
827
        // ### cache
        ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
828
        object->setClassName(QLatin1String("Point"));
829
830
831
        object->setProperty("x", engine()->numberValue());
        object->setProperty("y", engine()->numberValue());
        value = object;
832
833
834
835
836
837
838
839
    } else if (typeName == QLatin1String("QSize")
            || typeName == QLatin1String("QSizeF")) {
        // ### cache
        ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
        object->setClassName(QLatin1String("Size"));
        object->setProperty("width", engine()->numberValue());
        object->setProperty("height", engine()->numberValue());
        value = object;
840
841
    } else if (typeName == QLatin1String("QRect")
            || typeName == QLatin1String("QRectF")) {
842
843
        // ### cache
        ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
844
        object->setClassName("Rect");
845
846
847
848
849
        object->setProperty("x", engine()->numberValue());
        object->setProperty("y", engine()->numberValue());
        object->setProperty("width", engine()->numberValue());
        object->setProperty("height", engine()->numberValue());
        value = object;
850
    } else if (typeName == QLatin1String("QVector3D")) {
851
852
        // ### cache
        ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
853
        object->setClassName(QLatin1String("Vector3D"));
854
855
856
857
        object->setProperty("x", engine()->numberValue());
        object->setProperty("y", engine()->numberValue());
        object->setProperty("z", engine()->numberValue());
        value = object;
858
    } else if (typeName == QLatin1String("QColor")) {
859
        value = engine()->colorValue();
860
    } else if (typeName == QLatin1String("QDeclarativeAnchorLine")) {
861
        value = engine()->anchorLineValue();
862
863
    }

Christian Kamm's avatar
Christian Kamm committed
864
865
866
867
868
869
870
    // might be an enum
    int enumIndex = _metaObject->enumeratorIndex(prop.typeName());
    if (enumIndex != -1) {
        const FakeMetaEnum &metaEnum = _metaObject->enumerator(enumIndex);
        value = new QmlEnumValue(metaEnum, engine());
    }

871
872
    return value;
}
873

874
875
876
QString QmlObjectValue::packageName() const
{ return _metaObject->packageName(); }

877
878
QmlJS::ComponentVersion QmlObjectValue::version() const
{ return _metaObject->version(); }
879

880
881
882
QString QmlObjectValue::defaultPropertyName() const
{ return _metaObject->defaultPropertyName(); }

883
884
885
886
887
888
889
890
891
892
893
QString QmlObjectValue::propertyType(const QString &propertyName) const
{
    for (const FakeMetaObject *iter = _metaObject; iter; iter = iter->superClass()) {
        int propIdx = _metaObject->propertyIndex(propertyName);
        if (propIdx != -1) {
            return _metaObject->property(propIdx).typeName();
        }
    }
    return QString();
}

894
895
896
897
898
899
900
901
902
bool QmlObjectValue::isListProperty(const QString &name) const
{
    int idx = _metaObject->propertyIndex(name);
    if (idx == -1)
        return false;
    FakeMetaProperty prop = _metaObject->property(idx);
    return prop.isList();
}

903
904
905
906
907
bool QmlObjectValue::isEnum(const QString &typeName) const
{
    return _metaObject->enumeratorIndex(typeName) != -1;
}

908
909
910
911
912
913
914
915
916
917
918
919
920
bool QmlObjectValue::enumContainsKey(const QString &enumName, const QString &enumKeyName) const
{
    int idx = _metaObject->enumeratorIndex(enumName);
    if (idx == -1)
        return false;
    const FakeMetaEnum &fme = _metaObject->enumerator(idx);
    for (int i = 0; i < fme.keyCount(); ++i) {
        if (fme.key(i) == enumKeyName)
            return true;
    }
    return false;
}

921
922
923
924
925
926
// Returns true if this object is in a package or if there is an object that
// has this one in its prototype chain and is itself in a package.
bool QmlObjectValue::hasChildInPackage() const
{
    if (!packageName().isEmpty())
        return true;
927
    QHashIterator<QString, QmlObjectValue *> it(engine()->cppQmlTypes().types());
928
929
    while (it.hasNext()) {
        it.next();
930
        const FakeMetaObject *other = it.value()->_metaObject;
931
932
933
934
935
936
937
938
939
940
        if (other->packageName().isEmpty())
            continue;
        for (const FakeMetaObject *iter = other; iter; iter = iter->superClass()) {
            if (iter == _metaObject) // this object is a parent of other
                return true;
        }
    }
    return false;
}

941
bool QmlObjectValue::isDerivedFrom(const FakeMetaObject *base) const
942
{
943
    for (const FakeMetaObject *iter = _metaObject; iter; iter = iter->superClass()) {
944
945
946
947
948
949
        if (iter == base)
            return true;
    }
    return false;
}

Christian Kamm's avatar
Christian Kamm committed
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
QmlEnumValue::QmlEnumValue(const FakeMetaEnum &metaEnum, Engine *engine)
    : NumberValue(),
      _metaEnum(new FakeMetaEnum(metaEnum))
{
    engine->registerValue(this);
}

QmlEnumValue::~QmlEnumValue()
{
    delete _metaEnum;
}

QString QmlEnumValue::name() const
{
    return _metaEnum->name();
}

QStringList QmlEnumValue::keys() const
{
    return _metaEnum->keys();
}

972
973
namespace {

Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
974
975
976
977
978
979
980
981
////////////////////////////////////////////////////////////////////////////////
// constructors
////////////////////////////////////////////////////////////////////////////////
class ObjectCtor: public Function
{
public:
    ObjectCtor(Engine *engine);

Roberto Raggi's avatar
Roberto Raggi committed
982
    virtual const Value *invoke(const Activation *activation) const;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
983
984
985
986
987
988
989
};

class FunctionCtor: public Function
{
public:
    FunctionCtor(Engine *engine);

Roberto Raggi's avatar
Roberto Raggi committed
990
    virtual const Value *invoke(const Activation *activation) const;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
991
992
993
994
995
996
997
};

class ArrayCtor: public Function
{
public:
    ArrayCtor(Engine *engine);

Roberto Raggi's avatar
Roberto Raggi committed
998
    virtual const Value *invoke(const Activation *activation) const;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
999
1000
1001
1002
1003
1004
1005
};

class StringCtor: public Function
{
public:
    StringCtor(Engine *engine);

Roberto Raggi's avatar
Roberto Raggi committed
1006
    virtual const Value *invoke(const Activation *activation) const;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1007
1008
1009
1010
1011
1012
1013
};

class BooleanCtor: public Function
{
public:
    BooleanCtor(Engine *engine);

Roberto Raggi's avatar
Roberto Raggi committed
1014
    virtual const Value *invoke(const Activation *activation) const;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1015
1016
1017
1018
1019
1020
1021
};

class NumberCtor: public Function
{
public:
    NumberCtor(Engine *engine);

Roberto Raggi's avatar
Roberto Raggi committed
1022
    virtual const Value *invoke(const Activation *activation) const;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1023
1024
1025
1026
1027
1028
1029
};

class DateCtor: public Function
{
public:
    DateCtor(Engine *engine);

Roberto Raggi's avatar
Roberto Raggi committed
1030
    virtual const Value *invoke(const Activation *activation) const;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1031
1032
1033
1034
1035
1036
1037
};

class RegExpCtor: public Function
{
public:
    RegExpCtor(Engine *engine);

Roberto Raggi's avatar
Roberto Raggi committed
1038
    virtual const Value *invoke(const Activation *activation) const;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
};

ObjectCtor::ObjectCtor(Engine *engine)
    : Function(engine)
{
}

FunctionCtor::FunctionCtor(Engine *engine)
    : Function(engine)
{
}

ArrayCtor::ArrayCtor(Engine *engine)
    : Function(engine)
{
}

StringCtor::StringCtor(Engine *engine)
    : Function(engine)
{
}

BooleanCtor::BooleanCtor(Engine *engine)
    : Function(engine)
{
}

NumberCtor::NumberCtor(Engine *engine)
    : Function(engine)
{
}

DateCtor::DateCtor(Engine *engine)
    : Function(engine)
{
}

RegExpCtor::RegExpCtor(Engine *engine)
    : Function(engine)
{
}

Roberto Raggi's avatar
Roberto Raggi committed
1081
const Value *ObjectCtor::invoke(const Activation *activation) const
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1082
{
Roberto Raggi's avatar
Roberto Raggi committed
1083
1084
1085
1086
1087
1088
1089
1090
    ObjectValue *thisObject = activation->thisObject();
    if (activation->calledAsFunction())
        thisObject = engine()->newObject();

    thisObject->setClassName("Object");
    thisObject->setPrototype(engine()->objectPrototype());
    thisObject->setProperty("length", engine()->numberValue());
    return thisObject;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1091
1092
}

Roberto Raggi's avatar
Roberto Raggi committed
1093
const Value *FunctionCtor::invoke(const Activation *activation) const
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1094
{
Roberto Raggi's avatar
Roberto Raggi committed
1095
1096
1097
1098
1099
1100
1101
1102
    ObjectValue *thisObject = activation->thisObject();
    if (activation->calledAsFunction())
        thisObject = engine()->newObject();

    thisObject->setClassName("Function");
    thisObject->setPrototype(engine()->functionPrototype());
    thisObject->setProperty("length", engine()->numberValue());
    return thisObject;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1103
1104
}

Roberto Raggi's avatar
Roberto Raggi committed
1105
const Value *ArrayCtor::invoke(const Activation *activation) const
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1106
{
Roberto Raggi's avatar
Roberto Raggi committed
1107
1108
1109
    ObjectValue *thisObject = activation->thisObject();
    if (activation->calledAsFunction())
        thisObject = engine()->newObject();
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1110

Roberto Raggi's avatar
Roberto Raggi committed
1111
1112
1113
1114
    thisObject->setClassName("Array");
    thisObject->setPrototype(engine()->arrayPrototype());
    thisObject->setProperty("length", engine()->numberValue());
    return thisObject;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1115
1116
}

Roberto Raggi's avatar
Roberto Raggi committed
1117
const Value *StringCtor::invoke(const Activation *activation) const
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1118
{
Roberto Raggi's avatar
Roberto Raggi committed
1119
1120
    if (activation->calledAsFunction())
        return engine()->convertToString(activation->thisObject());
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1121

Roberto Raggi's avatar
Roberto Raggi committed
1122
1123
1124
1125
1126
    ObjectValue *thisObject = activation->thisObject();
    thisObject->setClassName("String");
    thisObject->setPrototype(engine()->stringPrototype());
    thisObject->setProperty("length", engine()->numberValue());
    return thisObject;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1127
1128
}

Roberto Raggi's avatar
Roberto Raggi committed
1129
const Value *BooleanCtor::invoke(const Activation *activation) const
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1130
{
Roberto Raggi's avatar
Roberto Raggi committed
1131
1132
1133
1134
1135
1136
1137
    if (activation->calledAsFunction())
        return engine()->convertToBoolean(activation->thisObject());

    ObjectValue *thisObject = activation->thisObject();
    thisObject->setClassName("Boolean");
    thisObject->setPrototype(engine()->booleanPrototype());
    return thisObject;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1138
1139
}

Roberto Raggi's avatar
Roberto Raggi committed
1140
const Value *NumberCtor::invoke(const Activation *activation) const
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1141
{
Roberto Raggi's avatar
Roberto Raggi committed
1142
1143
1144
1145
1146
1147
1148
    if (activation->calledAsFunction())
        return engine()->convertToNumber(activation->thisObject());

    ObjectValue *thisObject = activation->thisObject();
    thisObject->setClassName("Number");
    thisObject->setPrototype(engine()->numberPrototype());
    return thisObject;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1149
1150
}

Roberto Raggi's avatar
Roberto Raggi committed
1151
const Value *DateCtor::invoke(const Activation *activation) const
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1152
{
Roberto Raggi's avatar
Roberto Raggi committed
1153
1154
1155
1156
1157
1158
1159
    if (activation->calledAsFunction())
        return engine()->stringValue();

    ObjectValue *thisObject = activation->thisObject();
    thisObject->setClassName("Date");
    thisObject->setPrototype(engine()->datePrototype());
    return thisObject;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1160
1161
}

Roberto Raggi's avatar
Roberto Raggi committed
1162
const Value *RegExpCtor::invoke(const Activation *activation) const
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1163
{
Roberto Raggi's avatar
Roberto Raggi committed
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
    ObjectValue *thisObject = activation->thisObject();
    if (activation->calledAsFunction())
        thisObject = engine()->newObject();

    thisObject->setClassName("RegExp");
    thisObject->setPrototype(engine()->regexpPrototype());
    thisObject->setProperty("source", engine()->stringValue());
    thisObject->setProperty("global", engine()->booleanValue());
    thisObject->setProperty("ignoreCase", engine()->booleanValue());
    thisObject->setProperty("multiline", engine()->booleanValue());
    thisObject->setProperty("lastIndex", engine()->numberValue());
    return thisObject;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1176
1177
1178
1179
}

} // end of anonymous namespace

1180
1181
1182
////////////////////////////////////////////////////////////////////////////////
// ValueVisitor
////////////////////////////////////////////////////////////////////////////////
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
ValueVisitor::ValueVisitor()
{
}

ValueVisitor::~ValueVisitor()
{
}

void ValueVisitor::visit(const NullValue *)
{
}

void ValueVisitor::visit(const UndefinedValue *)
{
}

void ValueVisitor::visit(const NumberValue *)
{
}

void ValueVisitor::visit(const BooleanValue *)
{
}

void ValueVisitor::visit(const StringValue *)
{
}

void ValueVisitor::visit(const ObjectValue *)
{
}

void ValueVisitor::visit(const FunctionValue *)
{
}
1218

Roberto Raggi's avatar
Roberto Raggi committed
1219
1220
1221
void ValueVisitor::visit(const Reference *)
{
}
1222

1223
1224
1225
1226
void ValueVisitor::visit(const ColorValue *)
{
}

1227
1228
1229
1230
void ValueVisitor::visit(const AnchorLineValue *)
{
}

1231
1232
1233
////////////////////////////////////////////////////////////////////////////////
// Value
////////////////////////////////////////////////////////////////////////////////
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1234
1235
1236
1237
1238
1239
1240
1241
Value::Value()
{
}

Value::~Value()
{
}

1242
1243
1244
1245
1246
bool Value::getSourceLocation(QString *, int *, int *) const
{
    return false;
}

Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
const NullValue *Value::asNullValue() const
{
    return 0;
}

const UndefinedValue *Value::asUndefinedValue() const
{
    return 0;
}

const NumberValue *Value::asNumberValue() const
{
    return 0;
}

const BooleanValue *Value::asBooleanValue() const
{
    return 0;
}

const StringValue *Value::asStringValue() const
{
    return 0;
}

const ObjectValue *Value::asObjectValue() const
{
    return 0;
}

const FunctionValue *Value::asFunctionValue() const
{
    return 0;
}
1281