qmljsinterpreter.cpp 55.7 KB
Newer Older
1
2
3
4
5
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
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** 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 "qmljscheck.h"
32
#include "qmljslink.h"
33
#include "parser/qmljsast_p.h"
34
35
#include <QtCore/QMetaObject>
#include <QtCore/QMetaProperty>
36
37
#include <QtCore/QDebug>

Roberto Raggi's avatar
Roberto Raggi committed
38
39
40
41
#ifndef NO_DECLARATIVE_BACKEND
#  include <QtDeclarative/QmlType>
#  include <QtDeclarative/QmlMetaType>
#  include <QtDeclarative/private/qmlgraphicsanchors_p.h> // ### remove me
42
43
#  include <QtDeclarative/private/qmlgraphicsrectangle_p.h> // ### remove me
#  include <QtDeclarative/private/qmlvaluetype_p.h> // ### remove me
Roberto Raggi's avatar
Roberto Raggi committed
44
45
#endif

46
using namespace QmlJS::Interpreter;
47
using namespace QmlJS::AST;
48

Roberto Raggi's avatar
Roberto Raggi committed
49
50
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
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

Roberto Raggi's avatar
Roberto Raggi committed
103
104
#ifndef NO_DECLARATIVE_BACKEND

Roberto Raggi's avatar
Roberto Raggi committed
105
106
namespace {

107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
class MetaFunction: public FunctionValue
{
    QMetaMethod _method;

public:
    MetaFunction(const QMetaMethod &method, Engine *engine)
        : 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();
    }
};

Roberto Raggi's avatar
Roberto Raggi committed
151
152
} // end of anonymous namespace

153
154
155
156
157
158
159
QmlObjectValue::QmlObjectValue(const QMetaObject *metaObject, const QString &qmlTypeName,
                               int majorVersion, int minorVersion, Engine *engine)
    : ObjectValue(engine),
      _metaObject(metaObject),
      _qmlTypeName(qmlTypeName),
      _majorVersion(majorVersion),
      _minorVersion(minorVersion)
160
161
162
{
    setClassName(qmlTypeName); // ### TODO: we probably need to do more than just this...
}
Roberto Raggi's avatar
Roberto Raggi committed
163

164
QmlObjectValue::~QmlObjectValue() {}
Roberto Raggi's avatar
Roberto Raggi committed
165

166
const Value *QmlObjectValue::lookupMember(const QString &name, Context *context) const
167
{
168
    return ObjectValue::lookupMember(name, context);
Roberto Raggi's avatar
Roberto Raggi committed
169
}
170

Roberto Raggi's avatar
Roberto Raggi committed
171
172
173
const Value *QmlObjectValue::findOrCreateSignature(int index, const QMetaMethod &method, QString *methodName) const
{
    const QString signature = QString::fromUtf8(method.signature());
174

Roberto Raggi's avatar
Roberto Raggi committed
175
176
177
    const int indexOfParen = signature.indexOf(QLatin1Char('('));
    if (indexOfParen == -1)
        return engine()->undefinedValue(); // skip it, invalid signature.
178

Roberto Raggi's avatar
Roberto Raggi committed
179
180
181
182
183
    *methodName = signature.left(indexOfParen);
    const Value *value = _metaSignature.value(index);
    if (! value) {
        value = new MetaFunction(method, engine());
        _metaSignature.insert(index, value);
Roberto Raggi's avatar
Roberto Raggi committed
184
    }
Roberto Raggi's avatar
Roberto Raggi committed
185
    return value;
186
}
Roberto Raggi's avatar
Roberto Raggi committed
187

188
189
void QmlObjectValue::processMembers(MemberProcessor *processor) const
{
Roberto Raggi's avatar
Roberto Raggi committed
190
    // process the meta enums
191
192
193
194
195
196
197
198
    for (int index = _metaObject->enumeratorOffset(); index < _metaObject->propertyCount(); ++index) {
        QMetaEnum e = _metaObject->enumerator(index);

        for (int i = 0; i < e.keyCount(); ++i) {
            processor->processEnumerator(QString::fromUtf8(e.key(i)), engine()->numberValue());
        }
    }

Roberto Raggi's avatar
Roberto Raggi committed
199
200
201
    // process the meta properties
    for (int index = 0; index < _metaObject->propertyCount(); ++index) {
        QMetaProperty prop = _metaObject->property(index);
202

Roberto Raggi's avatar
Roberto Raggi committed
203
204
        processor->processProperty(prop.name(), propertyValue(prop));
    }
205

Roberto Raggi's avatar
Roberto Raggi committed
206
207
208
209
210
    // process the meta methods
    for (int index = 0; index < _metaObject->methodCount(); ++index) {
        QMetaMethod method = _metaObject->method(index);
        QString methodName;
        const Value *signature = findOrCreateSignature(index, method, &methodName);
211

212
        if (method.methodType() == QMetaMethod::Slot && method.access() == QMetaMethod::Public) {
Roberto Raggi's avatar
Roberto Raggi committed
213
            processor->processSlot(methodName, signature);
214

215
216
        } else if (method.methodType() == QMetaMethod::Signal && method.access() != QMetaMethod::Private) {
            // process the signal
Roberto Raggi's avatar
Roberto Raggi committed
217
            processor->processSignal(methodName, signature);
218

219
220
221
222
            QString slotName;
            slotName += QLatin1String("on");
            slotName += methodName.at(0).toUpper();
            slotName += methodName.midRef(1);
223

224
            // process the generated slot
Roberto Raggi's avatar
Roberto Raggi committed
225
            processor->processGeneratedSlot(slotName, signature);
226
        }
Roberto Raggi's avatar
Roberto Raggi committed
227
228
    }

229
230
231
232
233
234
235
    ObjectValue::processMembers(processor);
}

const Value *QmlObjectValue::propertyValue(const QMetaProperty &prop) const
{
    if (QmlMetaType::isObject(prop.userType())) {
        QmlType *qmlPropertyType = QmlMetaType::qmlType(QmlMetaType::metaObjectForType(prop.userType()));
Roberto Raggi's avatar
Roberto Raggi committed
236

237
238
239
240
241
242
243
244
245
246
247
248
        if (qmlPropertyType && !qmlPropertyType->qmlTypeName().isEmpty()) {
            QString typeName = qmlPropertyType->qmlTypeName();
            int slashIdx = typeName.lastIndexOf(QLatin1Char('/'));
            QString package;
            if (slashIdx != -1) {
                package = typeName.left(slashIdx);
                typeName = typeName.mid(slashIdx + 1);
            }

            if (const ObjectValue *objectValue = engine()->newQmlObject(typeName, package, qmlPropertyType->majorVersion(), qmlPropertyType->minorVersion()))
                return objectValue;
        } else {
Roberto Raggi's avatar
Roberto Raggi committed
249
250
251
252
253
254
255
            QString typeName = QString::fromUtf8(prop.typeName());

            if (typeName.endsWith(QLatin1Char('*')))
                typeName.truncate(typeName.length() - 1);

            typeName.replace(QLatin1Char('.'), QLatin1Char('/'));

256
            if (const ObjectValue *objectValue = engine()->newQmlObject(typeName, "", -1, -1))  // ### we should extend this to lookup the property types in the QmlType object, instead of the QMetaProperty.
Roberto Raggi's avatar
Roberto Raggi committed
257
258
259
260
                return objectValue;
        }
    }

261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
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
    const Value *value = engine()->undefinedValue();

    switch (prop.type()) {
    case QMetaType::QByteArray:
    case QMetaType::QString:
    case QMetaType::QUrl:
        value = engine()->stringValue();
        break;

    case QMetaType::Bool:
        value = engine()->booleanValue();
        break;

    case QMetaType::Int:
    case QMetaType::Float:
    case QMetaType::Double:
        value = engine()->numberValue();
        break;

    case QMetaType::QFont: {
        // ### cache
        ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
        object->setProperty("family", engine()->stringValue());
        object->setProperty("weight", engine()->undefinedValue()); // ### make me an object
        object->setProperty("copitalization", engine()->undefinedValue()); // ### make me an object
        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;
    } break;

    case QMetaType::QPoint:
    case QMetaType::QPointF: {
        // ### cache
        ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
        object->setProperty("x", engine()->numberValue());
        object->setProperty("y", engine()->numberValue());
        value = object;
    } break;

    case QMetaType::QRect:
    case QMetaType::QRectF: {
        // ### cache
        ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
        object->setProperty("x", engine()->numberValue());
        object->setProperty("y", engine()->numberValue());
        object->setProperty("width", engine()->numberValue());
        object->setProperty("height", engine()->numberValue());
        value = object;
    } break;

    default:
        break;
    } // end of switch

    return value;
}
Roberto Raggi's avatar
Roberto Raggi committed
324
325
#endif

326
327
namespace {

Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
328
329
330
331
332
333
334
335
////////////////////////////////////////////////////////////////////////////////
// constructors
////////////////////////////////////////////////////////////////////////////////
class ObjectCtor: public Function
{
public:
    ObjectCtor(Engine *engine);

Roberto Raggi's avatar
Roberto Raggi committed
336
    virtual const Value *invoke(const Activation *activation) const;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
337
338
339
340
341
342
343
};

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

Roberto Raggi's avatar
Roberto Raggi committed
344
    virtual const Value *invoke(const Activation *activation) const;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
345
346
347
348
349
350
351
};

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

Roberto Raggi's avatar
Roberto Raggi committed
352
    virtual const Value *invoke(const Activation *activation) const;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
353
354
355
356
357
358
359
};

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

Roberto Raggi's avatar
Roberto Raggi committed
360
    virtual const Value *invoke(const Activation *activation) const;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
361
362
363
364
365
366
367
};

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

Roberto Raggi's avatar
Roberto Raggi committed
368
    virtual const Value *invoke(const Activation *activation) const;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
369
370
371
372
373
374
375
};

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

Roberto Raggi's avatar
Roberto Raggi committed
376
    virtual const Value *invoke(const Activation *activation) const;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
377
378
379
380
381
382
383
};

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

Roberto Raggi's avatar
Roberto Raggi committed
384
    virtual const Value *invoke(const Activation *activation) const;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
385
386
387
388
389
390
391
};

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

Roberto Raggi's avatar
Roberto Raggi committed
392
    virtual const Value *invoke(const Activation *activation) const;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
};

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
435
const Value *ObjectCtor::invoke(const Activation *activation) const
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
436
{
Roberto Raggi's avatar
Roberto Raggi committed
437
438
439
440
441
442
443
444
    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
445
446
}

Roberto Raggi's avatar
Roberto Raggi committed
447
const Value *FunctionCtor::invoke(const Activation *activation) const
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
448
{
Roberto Raggi's avatar
Roberto Raggi committed
449
450
451
452
453
454
455
456
    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
457
458
}

Roberto Raggi's avatar
Roberto Raggi committed
459
const Value *ArrayCtor::invoke(const Activation *activation) const
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
460
{
Roberto Raggi's avatar
Roberto Raggi committed
461
462
463
    ObjectValue *thisObject = activation->thisObject();
    if (activation->calledAsFunction())
        thisObject = engine()->newObject();
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
464

Roberto Raggi's avatar
Roberto Raggi committed
465
466
467
468
    thisObject->setClassName("Array");
    thisObject->setPrototype(engine()->arrayPrototype());
    thisObject->setProperty("length", engine()->numberValue());
    return thisObject;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
469
470
}

Roberto Raggi's avatar
Roberto Raggi committed
471
const Value *StringCtor::invoke(const Activation *activation) const
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
472
{
Roberto Raggi's avatar
Roberto Raggi committed
473
474
    if (activation->calledAsFunction())
        return engine()->convertToString(activation->thisObject());
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
475

Roberto Raggi's avatar
Roberto Raggi committed
476
477
478
479
480
    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
481
482
}

Roberto Raggi's avatar
Roberto Raggi committed
483
const Value *BooleanCtor::invoke(const Activation *activation) const
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
484
{
Roberto Raggi's avatar
Roberto Raggi committed
485
486
487
488
489
490
491
    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
492
493
}

Roberto Raggi's avatar
Roberto Raggi committed
494
const Value *NumberCtor::invoke(const Activation *activation) const
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
495
{
Roberto Raggi's avatar
Roberto Raggi committed
496
497
498
499
500
501
502
    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
503
504
}

Roberto Raggi's avatar
Roberto Raggi committed
505
const Value *DateCtor::invoke(const Activation *activation) const
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
506
{
Roberto Raggi's avatar
Roberto Raggi committed
507
508
509
510
511
512
513
    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
514
515
}

Roberto Raggi's avatar
Roberto Raggi committed
516
const Value *RegExpCtor::invoke(const Activation *activation) const
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
517
{
Roberto Raggi's avatar
Roberto Raggi committed
518
519
520
521
522
523
524
525
526
527
528
529
    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
530
531
532
533
}

} // end of anonymous namespace

534
535
536
////////////////////////////////////////////////////////////////////////////////
// ValueVisitor
////////////////////////////////////////////////////////////////////////////////
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
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
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 *)
{
}
572

Roberto Raggi's avatar
Roberto Raggi committed
573
574
575
void ValueVisitor::visit(const Reference *)
{
}
576
577
578
579

////////////////////////////////////////////////////////////////////////////////
// Value
////////////////////////////////////////////////////////////////////////////////
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
580
581
582
583
584
585
586
587
Value::Value()
{
}

Value::~Value()
{
}

588
589
590
591
592
bool Value::getSourceLocation(QString *, int *, int *) const
{
    return false;
}

Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
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
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;
}
627

Roberto Raggi's avatar
Roberto Raggi committed
628
629
630
631
632
const Reference *Value::asReference() const
{
    return 0;
}

633
634
635
////////////////////////////////////////////////////////////////////////////////
// Values
////////////////////////////////////////////////////////////////////////////////
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
const NullValue *NullValue::asNullValue() const
{
    return this;
}

void NullValue::accept(ValueVisitor *visitor) const
{
    visitor->visit(this);
}

const UndefinedValue *UndefinedValue::asUndefinedValue() const
{
    return this;
}

void UndefinedValue::accept(ValueVisitor *visitor) const
{
    visitor->visit(this);
}
655

Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
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
const NumberValue *NumberValue::asNumberValue() const
{
    return this;
}

void NumberValue::accept(ValueVisitor *visitor) const
{
    visitor->visit(this);
}

const BooleanValue *BooleanValue::asBooleanValue() const
{
    return this;
}

void BooleanValue::accept(ValueVisitor *visitor) const
{
    visitor->visit(this);
}

const StringValue *StringValue::asStringValue() const
{
    return this;
}

void StringValue::accept(ValueVisitor *visitor) const
{
    visitor->visit(this);
}

Roberto Raggi's avatar
Roberto Raggi committed
686
687

Context::Context(Engine *engine)
688
689
    : _engine(engine),
      _lookupMode(JSLookup)
Roberto Raggi's avatar
Roberto Raggi committed
690
691
692
693
694
695
696
{
}

Context::~Context()
{
}

Tobias Hunger's avatar
Tobias Hunger committed
697
void Context::build(Node *node, QmlJS::Document::Ptr doc, const QmlJS::Snapshot &snapshot)
698
699
700
701
702
{
    Link link(this, doc, snapshot);
    link.scopeChainAt(doc, node);
}

Roberto Raggi's avatar
Roberto Raggi committed
703
704
705
706
707
Engine *Context::engine() const
{
    return _engine;
}

708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
Context::ScopeChain Context::scopeChain() const
{
    return _scopeChain;
}

Context::LookupMode Context::lookupMode() const
{
    return _lookupMode;
}

void Context::setLookupMode(LookupMode lookupMode)
{
    _lookupMode = lookupMode;
}

Tobias Hunger's avatar
Tobias Hunger committed
723
const ObjectValue *Context::typeEnvironment(const QmlJS::Document *doc) const
724
{
725
    return _typeEnvironments.value(doc, 0);
726
727
}

Tobias Hunger's avatar
Tobias Hunger committed
728
void Context::setTypeEnvironment(const QmlJS::Document *doc, const ObjectValue *typeEnvironment)
729
{
730
    _typeEnvironments[doc] = typeEnvironment;
731
732
}

733
734
735
736
737
738
739
740
741
742
void Context::pushScope(const ObjectValue *object)
{
    _scopeChain.append(object);
}

void Context::popScope()
{
    _scopeChain.removeLast();
}

743
const Value *Context::lookup(const QString &name)
744
745
746
747
{
    for (int index = _scopeChain.size() - 1; index != -1; --index) {
        const ObjectValue *scope = _scopeChain.at(index);

748
        if (const Value *member = scope->lookupMember(name, this)) {
749
750
751
752
753
754
755
756
757
            if (_lookupMode == JSLookup || ! dynamic_cast<const ASTVariableReference *>(member)) {
                return member;
            }
        }
    }

    return _engine->undefinedValue();
}

Tobias Hunger's avatar
Tobias Hunger committed
758
const ObjectValue *Context::lookupType(const QmlJS::Document *doc, UiQualifiedId *qmlTypeName)
759
{
760
    const ObjectValue *objectValue = typeEnvironment(doc);
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775

    for (UiQualifiedId *iter = qmlTypeName; objectValue && iter; iter = iter->next) {
        if (! iter->name)
            return 0;

        const Value *value = objectValue->property(iter->name->asString(), this);
        if (!value)
            return 0;

        objectValue = value->asObjectValue();
    }

    return objectValue;
}

Roberto Raggi's avatar
Roberto Raggi committed
776
777
778
779
780
781
782
783
784
785
786
const Value *Context::property(const ObjectValue *object, const QString &name) const
{
    const Properties properties = _properties.value(object);
    return properties.value(name, engine()->undefinedValue());
}

void Context::setProperty(const ObjectValue *object, const QString &name, const Value *value)
{
    _properties[object].insert(name, value);
}

787
788
Reference::Reference(Engine *engine)
    : _engine(engine)
Roberto Raggi's avatar
Roberto Raggi committed
789
{
790
    _engine->registerValue(this);
Roberto Raggi's avatar
Roberto Raggi committed
791
792
793
794
795
796
}

Reference::~Reference()
{
}

797
798
799
800
801
Engine *Reference::engine() const
{
    return _engine;
}

Roberto Raggi's avatar
Roberto Raggi committed
802
803
804
805
806
807
808
809
810
811
const Reference *Reference::asReference() const
{
    return this;
}

void Reference::accept(ValueVisitor *visitor) const
{
    visitor->visit(this);
}

812
813
814
815
const Value *Reference::value(Context *) const
{
    return _engine->undefinedValue();
}
Roberto Raggi's avatar
Roberto Raggi committed
816

817
818
819
820
821
822
823
824
825
826
827
828
829
MemberProcessor::MemberProcessor()
{
}

MemberProcessor::~MemberProcessor()
{
}

bool MemberProcessor::processProperty(const QString &, const Value *)
{
    return true;
}

830
831
832
833
834
bool MemberProcessor::processEnumerator(const QString &, const Value *)
{
    return true;
}

835
836
837
838
839
840
841
842
843
844
bool MemberProcessor::processSignal(const QString &, const Value *)
{
    return true;
}

bool MemberProcessor::processSlot(const QString &, const Value *)
{
    return true;
}

845
846
847
848
849
bool MemberProcessor::processGeneratedSlot(const QString &, const Value *)
{
    return true;
}

Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
850
ObjectValue::ObjectValue(Engine *engine)
851
    : _engine(engine),
852
      _prototype(0)
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
853
{
854
    engine->registerValue(this);
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
}

ObjectValue::~ObjectValue()
{
}

Engine *ObjectValue::engine() const
{
    return _engine;
}

QString ObjectValue::className() const
{
    return _className;
}

void ObjectValue::setClassName(const QString &className)
{
    _className = className;
}

876
const ObjectValue *ObjectValue::prototype(Context *context) const
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
877
{
878
879
880
881
882
883
884
885
886
887
888
889
890
    const ObjectValue *prototypeObject = value_cast<const ObjectValue *>(_prototype);
    if (! prototypeObject) {
        if (const Reference *prototypeReference = value_cast<const Reference *>(_prototype)) {
            prototypeObject = value_cast<const ObjectValue *>(prototypeReference->value(context));
        }
    }
    return prototypeObject;
}

void ObjectValue::setPrototype(const Value *prototype)
{
    // ### FIXME: Check for cycles.
    _prototype = prototype;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
}

void ObjectValue::setProperty(const QString &name, const Value *value)
{
    _members[name] = value;
}

void ObjectValue::removeProperty(const QString &name)
{
    _members.remove(name);
}

const ObjectValue *ObjectValue::asObjectValue() const
{
    return this;
}

void ObjectValue::accept(ValueVisitor *visitor) const
{
    visitor->visit(this);
}

913
const Value *ObjectValue::property(const QString &name, Context *context) const
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
914
{
915
    return lookupMember(name, context);
916
917
}

918
bool ObjectValue::checkPrototype(const ObjectValue *, QSet<const ObjectValue *> *) const
919
{
920
#if 0
921
922
923
924
925
926
927
    const int previousSize = processed->size();
    processed->insert(this);

    if (previousSize != processed->size()) {
        if (this == proto)
            return false;

Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
928
        if (prototype() && ! prototype()->checkPrototype(proto, processed))
929
930
931
932
            return false;

        return true;
    }
933
#endif
934
935
936
    return false;
}

Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
937
938
939
940
941
942
943
void ObjectValue::processMembers(MemberProcessor *processor) const
{
    QHashIterator<QString, const Value *> it(_members);

    while (it.hasNext()) {
        it.next();

944
        if (! processor->processProperty(it.key(), it.value()))
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
945
946
947
948
            break;
    }
}

949
const Value *ObjectValue::lookupMember(const QString &name, Context *context) const
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
950
{
Roberto Raggi's avatar
Roberto Raggi committed
951
    if (const Value *m = _members.value(name))
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
952
        return m;
Roberto Raggi's avatar
Roberto Raggi committed
953
954
955
956
957
958
    else {
        LookupMember slowLookup(name);
        processMembers(&slowLookup);
        if (slowLookup.value())
            return slowLookup.value();
    }
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
959

960
961
962
    const ObjectValue *prototypeObject = prototype(context);
    if (prototypeObject) {
        if (const Value *m = prototypeObject->lookupMember(name, context))
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
963
964
965
966
967
968
            return m;
    }

    return 0;
}

969
Activation::Activation(Context *parentContext)
970
    : _thisObject(0),
971
972
      _calledAsFunction(true),
      _parentContext(parentContext)
Roberto Raggi's avatar
Roberto Raggi committed
973
974
975
976
977
978
979
{
}

Activation::~Activation()
{
}

980
981
982
983
984
985
986
987
988
989
990
Context *Activation::parentContext() const
{
    return _parentContext;
}

Context *Activation::context() const
{
    // ### FIXME: Real context for activations.
    return 0;
}

Roberto Raggi's avatar
Roberto Raggi committed
991
992
993
994
995
996
997
998
999
1000
bool Activation::calledAsConstructor() const
{
    return ! _calledAsFunction;
}

void Activation::setCalledAsConstructor(bool calledAsConstructor)
{
    _calledAsFunction = ! calledAsConstructor;
}