Newer
Older
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 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.
**
**************************************************************************/
#ifndef QMLJS_INTERPRETER_H
#define QMLJS_INTERPRETER_H
#include <qmljs/qmljsdocument.h>
#include <qmljs/parser/qmljsastfwd_p.h>

Erik Verbruggen
committed
#include <QtCore/QFileInfoList>
#include <QtCore/QList>
#include <QtCore/QString>
#include <QtCore/QHash>
#include <QtCore/QSet>
namespace QmlJS {
namespace Interpreter {
////////////////////////////////////////////////////////////////////////////////
// Forward declarations
////////////////////////////////////////////////////////////////////////////////
class Engine;
class Value;
class NullValue;
class UndefinedValue;
class NumberValue;
class BooleanValue;
class StringValue;
class ObjectValue;
class FunctionValue;
class AnchorLineValue;

Erik Verbruggen
committed
class FakeMetaObject;
class FakeMetaMethod;
class FakeMetaProperty;
////////////////////////////////////////////////////////////////////////////////
// Value visitor
////////////////////////////////////////////////////////////////////////////////
class QMLJS_EXPORT ValueVisitor
{
public:
ValueVisitor();
virtual ~ValueVisitor();
virtual void visit(const NullValue *);
virtual void visit(const UndefinedValue *);
virtual void visit(const NumberValue *);
virtual void visit(const BooleanValue *);
virtual void visit(const StringValue *);
virtual void visit(const ObjectValue *);
virtual void visit(const FunctionValue *);
virtual void visit(const EasingCurveNameValue *);
virtual void visit(const ColorValue *);
virtual void visit(const AnchorLineValue *);
};
////////////////////////////////////////////////////////////////////////////////
// QML/JS value
////////////////////////////////////////////////////////////////////////////////
class QMLJS_EXPORT Value
{
Value(const Value &other);
void operator = (const Value &other);
public:
Value();
virtual ~Value();
virtual const NullValue *asNullValue() const;
virtual const UndefinedValue *asUndefinedValue() const;
virtual const NumberValue *asNumberValue() const;
virtual const BooleanValue *asBooleanValue() const;
virtual const StringValue *asStringValue() const;
virtual const ObjectValue *asObjectValue() const;
virtual const FunctionValue *asFunctionValue() const;
virtual const Reference *asReference() const;
virtual const EasingCurveNameValue *asEasingCurveNameValue() const;
virtual const ColorValue *asColorValue() const;
virtual const AnchorLineValue *asAnchorLineValue() const;
virtual void accept(ValueVisitor *) const = 0;
virtual bool getSourceLocation(QString *fileName, int *line, int *column) const;
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
};
template <typename _RetTy> _RetTy value_cast(const Value *v);
template <> Q_INLINE_TEMPLATE const NullValue *value_cast(const Value *v)
{
if (v) return v->asNullValue();
else return 0;
}
template <> Q_INLINE_TEMPLATE const UndefinedValue *value_cast(const Value *v)
{
if (v) return v->asUndefinedValue();
else return 0;
}
template <> Q_INLINE_TEMPLATE const NumberValue *value_cast(const Value *v)
{
if (v) return v->asNumberValue();
else return 0;
}
template <> Q_INLINE_TEMPLATE const BooleanValue *value_cast(const Value *v)
{
if (v) return v->asBooleanValue();
else return 0;
}
template <> Q_INLINE_TEMPLATE const StringValue *value_cast(const Value *v)
{
if (v) return v->asStringValue();
else return 0;
}
template <> Q_INLINE_TEMPLATE const ObjectValue *value_cast(const Value *v)
{
if (v) return v->asObjectValue();
else return 0;
}
template <> Q_INLINE_TEMPLATE const FunctionValue *value_cast(const Value *v)
{
if (v) return v->asFunctionValue();
else return 0;
}
template <> Q_INLINE_TEMPLATE const Reference *value_cast(const Value *v)
{
if (v) return v->asReference();
else return 0;
}
template <> Q_INLINE_TEMPLATE const EasingCurveNameValue *value_cast(const Value *v)
{
if (v) return v->asEasingCurveNameValue();
else return 0;
}
template <> Q_INLINE_TEMPLATE const ColorValue *value_cast(const Value *v)
{
if (v) return v->asColorValue();
else return 0;
}
template <> Q_INLINE_TEMPLATE const AnchorLineValue *value_cast(const Value *v)
{
if (v) return v->asAnchorLineValue();
else return 0;
}
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
////////////////////////////////////////////////////////////////////////////////
// Value nodes
////////////////////////////////////////////////////////////////////////////////
class QMLJS_EXPORT NullValue: public Value
{
public:
virtual const NullValue *asNullValue() const;
virtual void accept(ValueVisitor *visitor) const;
};
class QMLJS_EXPORT UndefinedValue: public Value
{
public:
virtual const UndefinedValue *asUndefinedValue() const;
virtual void accept(ValueVisitor *visitor) const;
};
class QMLJS_EXPORT NumberValue: public Value
{
public:
virtual const NumberValue *asNumberValue() const;
virtual void accept(ValueVisitor *visitor) const;
};
class QMLJS_EXPORT BooleanValue: public Value
{
public:
virtual const BooleanValue *asBooleanValue() const;
virtual void accept(ValueVisitor *visitor) const;
};
class QMLJS_EXPORT StringValue: public Value
{
public:
virtual const StringValue *asStringValue() const;
virtual void accept(ValueVisitor *visitor) const;
};
class QMLJS_EXPORT MemberProcessor
{
MemberProcessor(const MemberProcessor &other);
void operator = (const MemberProcessor &other);
public:

Roberto Raggi
committed
MemberProcessor();
virtual ~MemberProcessor();

Roberto Raggi
committed
virtual bool processProperty(const QString &name, const Value *value);
virtual bool processEnumerator(const QString &name, const Value *value);

Roberto Raggi
committed
virtual bool processSignal(const QString &name, const Value *value);
virtual bool processSlot(const QString &name, const Value *value);
virtual bool processGeneratedSlot(const QString &name, const Value *value);
ScopeChain();
struct QmlComponentChain
{
QmlComponentChain();
~QmlComponentChain();
QList<QmlComponentChain *> instantiatingComponents;
const ObjectValue *rootObject;
QList<const ObjectValue *> functionScopes;
const ObjectValue *ids;
void add(QList<const ObjectValue *> *list) const;
};
const ObjectValue *globalScope;
QmlComponentChain qmlComponentScope;
QList<const ObjectValue *> qmlScopeObjects;
const ObjectValue *qmlTypes;
QList<const ObjectValue *> jsScopes;
// rebuilds the flat list of all scopes
void update();
QList<const ObjectValue *> all() const;
private:
QList<const ObjectValue *> _all;
};
class QMLJS_EXPORT Context
{
public:
enum LookupMode {
JSLookup,
QmlLookup
};
void build(const QList<AST::Node *> &astPath, const Document::Ptr doc,
const Snapshot &snapshot, const QStringList &importPaths);
const ScopeChain &scopeChain() const;
ScopeChain &scopeChain();
LookupMode lookupMode() const;
void setLookupMode(LookupMode lookupMode);
const ObjectValue *typeEnvironment(const Document *doc) const;
void setTypeEnvironment(const Document *doc, const ObjectValue *typeEnvironment);
const Value *lookup(const QString &name);
const ObjectValue *lookupType(const Document *doc, AST::UiQualifiedId *qmlTypeName);
const Value *property(const ObjectValue *object, const QString &name) const;
void setProperty(const ObjectValue *object, const QString &name, const Value *value);
private:
typedef QHash<QString, const Value *> Properties;
Engine *_engine;
QHash<const ObjectValue *, Properties> _properties;
QHash<QString, const ObjectValue *> _typeEnvironments;
ScopeChain _scopeChain;
int _qmlScopeObjectIndex;
bool _qmlScopeObjectSet;
};
class QMLJS_EXPORT Reference: public Value
{
public:
Engine *engine() const;
virtual const Value *value(Context *context) const;
// Value interface
virtual const Reference *asReference() const;
virtual void accept(ValueVisitor *) const;
private:
Engine *_engine;
class QMLJS_EXPORT EasingCurveNameValue: public Value
{
static QSet<QString> _curveNames;
public:
static QSet<QString> curveNames();
// Value interface
virtual const EasingCurveNameValue *asEasingCurveNameValue() const;
virtual void accept(ValueVisitor *) const;
};
class QMLJS_EXPORT ColorValue: public Value
{
public:
// Value interface
virtual const ColorValue *asColorValue() const;
virtual void accept(ValueVisitor *) const;
};
class QMLJS_EXPORT AnchorLineValue: public Value
{
public:
// Value interface
virtual const AnchorLineValue *asAnchorLineValue() const;
virtual void accept(ValueVisitor *) const;
};
class QMLJS_EXPORT ObjectValue: public Value
{
public:
ObjectValue(Engine *engine);
Engine *engine() const;
QString className() const;
void setClassName(const QString &className);
const ObjectValue *prototype(Context *context) const;
void setPrototype(const Value *prototype);
virtual const Value *property(const QString &name, Context *context) const;
virtual void setProperty(const QString &name, const Value *value);
virtual void removeProperty(const QString &name);

Erik Verbruggen
committed
virtual const Value *lookupMember(const QString &name, Context *context, bool examinePrototypes = true) const;
// Value interface
virtual const ObjectValue *asObjectValue() const;
virtual void accept(ValueVisitor *visitor) const;
private:
bool checkPrototype(const ObjectValue *prototype, QSet<const ObjectValue *> *processed) const;
private:
Engine *_engine;
QHash<QString, const Value *> _members;
QString _className;
};
class QMLJS_EXPORT QmlObjectValue: public ObjectValue

Erik Verbruggen
committed
static const int NoVersion;
public:
QmlObjectValue(const FakeMetaObject *metaObject, Engine *engine);
virtual ~QmlObjectValue();
virtual void processMembers(MemberProcessor *processor) const;

Erik Verbruggen
committed
const Value *propertyValue(const FakeMetaProperty &prop) const;

Erik Verbruggen
committed
QString packageName() const;
int majorVersion() const;
int minorVersion() const;
QString defaultPropertyName() const;

Erik Verbruggen
committed
QString propertyType(const QString &propertyName) const;
bool isListProperty(const QString &name) const;

Erik Verbruggen
committed
bool isEnum(const QString &typeName) const;

Erik Verbruggen
committed
const Value *findOrCreateSignature(int index, const FakeMetaMethod &method, QString *methodName) const;
bool isDerivedFrom(const FakeMetaObject *base) const;

Erik Verbruggen
committed
const FakeMetaObject *_metaObject;
mutable QHash<int, const Value *> _metaSignature;
class QMLJS_EXPORT Activation
explicit Activation(Context *parentContext = 0);
Context *context() const;
Context *parentContext() const;
bool calledAsConstructor() const;
void setCalledAsConstructor(bool calledAsConstructor);
bool calledAsFunction() const;
void setCalledAsFunction(bool calledAsFunction);
ObjectValue *thisObject() const;
void setThisObject(ObjectValue *thisObject);
ValueList arguments() const;
void setArguments(const ValueList &arguments);
private:
ObjectValue *_thisObject;
ValueList _arguments;
bool _calledAsFunction;
class QMLJS_EXPORT FunctionValue: public ObjectValue
{
public:
FunctionValue(Engine *engine);
virtual ~FunctionValue();
// [[construct]]
const Value *construct(const ValueList &actuals = ValueList()) const;
// [[call]]
const Value *call(const ValueList &actuals = ValueList()) const;
const Value *call(const ObjectValue *thisObject,
const ValueList &actuals = ValueList()) const;
virtual const Value *returnValue() const;
virtual int argumentCount() const;
virtual QString argumentName(int index) const;
virtual bool isVariadic() const;
virtual const Value *invoke(const Activation *activation) const;
// Value interface
virtual const FunctionValue *asFunctionValue() const;
virtual void accept(ValueVisitor *visitor) const;
};
class QMLJS_EXPORT Function: public FunctionValue
{
public:
Function(Engine *engine);
void addArgument(const Value *argument);
void setReturnValue(const Value *returnValue);
// ObjectValue interface
virtual const Value *property(const QString &name, Context *context) const;
// FunctionValue interface
virtual const Value *returnValue() const;
virtual int argumentCount() const;
virtual const Value *argument(int index) const;
virtual const Value *invoke(const Activation *activation) const;
const Value *_returnValue;
};
////////////////////////////////////////////////////////////////////////////////
// typing environment
////////////////////////////////////////////////////////////////////////////////

Erik Verbruggen
committed
class QMLJS_EXPORT MetaTypeSystem
{
static QList<const FakeMetaObject *> _metaObjects;
public:
/** \return an empty list when successful, error messages otherwise. */
static QStringList load(const QFileInfoList &xmlFiles);
void reload(Interpreter::Engine *interpreter);
QList<Interpreter::QmlObjectValue *> staticTypesForImport(const QString &prefix, int majorVersion, int minorVersion) const;
Interpreter::QmlObjectValue *staticTypeForImport(const QString &qualifiedName) const;
bool hasPackage(const QString &package) const;

Erik Verbruggen
committed
private:
QHash<QString, QList<QmlObjectValue *> > _importedTypes;
};
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
573
574
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
class ConvertToNumber: protected ValueVisitor // ECMAScript ToInt()
{
public:
ConvertToNumber(Engine *engine);
const Value *operator()(const Value *value);
protected:
const Value *switchResult(const Value *value);
virtual void visit(const NullValue *);
virtual void visit(const UndefinedValue *);
virtual void visit(const NumberValue *);
virtual void visit(const BooleanValue *);
virtual void visit(const StringValue *);
virtual void visit(const ObjectValue *);
virtual void visit(const FunctionValue *);
private:
Engine *_engine;
const Value *_result;
};
class ConvertToString: protected ValueVisitor // ECMAScript ToString
{
public:
ConvertToString(Engine *engine);
const Value *operator()(const Value *value);
protected:
const Value *switchResult(const Value *value);
virtual void visit(const NullValue *);
virtual void visit(const UndefinedValue *);
virtual void visit(const NumberValue *);
virtual void visit(const BooleanValue *);
virtual void visit(const StringValue *);
virtual void visit(const ObjectValue *);
virtual void visit(const FunctionValue *);
private:
Engine *_engine;
const Value *_result;
};
class ConvertToObject: protected ValueVisitor // ECMAScript ToObject
{
public:
ConvertToObject(Engine *engine);
const Value *operator()(const Value *value);
protected:
const Value *switchResult(const Value *value);
virtual void visit(const NullValue *);
virtual void visit(const UndefinedValue *);
virtual void visit(const NumberValue *);
virtual void visit(const BooleanValue *);
virtual void visit(const StringValue *);
virtual void visit(const ObjectValue *);
virtual void visit(const FunctionValue *);
private:
Engine *_engine;
const Value *_result;
};
class TypeId: protected ValueVisitor
{
QString _result;
public:
QString operator()(const Value *value);
protected:
virtual void visit(const NullValue *);
virtual void visit(const UndefinedValue *);
virtual void visit(const NumberValue *);
virtual void visit(const BooleanValue *);
virtual void visit(const StringValue *);
virtual void visit(const ObjectValue *object);
virtual void visit(const FunctionValue *object);
virtual void visit(const EasingCurveNameValue *);
virtual void visit(const ColorValue *);
virtual void visit(const AnchorLineValue *);
};
class QMLJS_EXPORT Engine
{
Engine(const Engine &other);
void operator = (const Engine &other);
public:
Engine();
~Engine();
const NullValue *nullValue() const;
const UndefinedValue *undefinedValue() const;
const NumberValue *numberValue() const;
const BooleanValue *booleanValue() const;
const StringValue *stringValue() const;
const EasingCurveNameValue *easingCurveNameValue() const;
const ColorValue *colorValue() const;
const AnchorLineValue *anchorLineValue() const;
ObjectValue *newObject(const ObjectValue *prototype);
ObjectValue *newObject();
Function *newFunction();
const ObjectValue *qmlKeysObject();

Roberto Raggi
committed
const Value *defaultValueForBuiltinType(const QString &typeName) const;
// global object
ObjectValue *globalObject() const;
const ObjectValue *mathObject() const;
const ObjectValue *qtObject() const;
// prototypes
ObjectValue *objectPrototype() const;
ObjectValue *functionPrototype() const;
ObjectValue *numberPrototype() const;
ObjectValue *booleanPrototype() const;
ObjectValue *stringPrototype() const;
ObjectValue *arrayPrototype() const;
ObjectValue *datePrototype() const;
ObjectValue *regexpPrototype() const;
// ctors
const FunctionValue *objectCtor() const;
const FunctionValue *functionCtor() const;
const FunctionValue *arrayCtor() const;
const FunctionValue *stringCtor() const;
const FunctionValue *booleanCtor() const;
const FunctionValue *numberCtor() const;
const FunctionValue *dateCtor() const;
const FunctionValue *regexpCtor() const;
// operators
const Value *convertToBoolean(const Value *value);
const Value *convertToNumber(const Value *value);
const Value *convertToString(const Value *value);
const Value *convertToObject(const Value *value);
QString typeId(const Value *value);
// typing:
const MetaTypeSystem &metaTypeSystem() const
{ return _metaTypeSystem; }
void registerValue(Value *value); // internal
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
private:
void initializePrototypes();
void addFunction(ObjectValue *object, const QString &name, const Value *result, int argumentCount);
void addFunction(ObjectValue *object, const QString &name, int argumentCount);
private:
ObjectValue *_objectPrototype;
ObjectValue *_functionPrototype;
ObjectValue *_numberPrototype;
ObjectValue *_booleanPrototype;
ObjectValue *_stringPrototype;
ObjectValue *_arrayPrototype;
ObjectValue *_datePrototype;
ObjectValue *_regexpPrototype;
Function *_objectCtor;
Function *_functionCtor;
Function *_arrayCtor;
Function *_stringCtor;
Function *_booleanCtor;
Function *_numberCtor;
Function *_dateCtor;
Function *_regexpCtor;
ObjectValue *_globalObject;
ObjectValue *_mathObject;
ObjectValue *_qmlKeysObject;
NullValue _nullValue;
UndefinedValue _undefinedValue;
NumberValue _numberValue;
BooleanValue _booleanValue;
StringValue _stringValue;
EasingCurveNameValue _easingCurveNameValue;
AnchorLineValue _anchorLineValue;
QList<Value *> _registeredValues;
ConvertToNumber _convertToNumber;
ConvertToString _convertToString;
ConvertToObject _convertToObject;
TypeId _typeId;
MetaTypeSystem _metaTypeSystem;
class QMLJS_EXPORT QmlPrototypeReference: public Reference
{
public:
QmlPrototypeReference(AST::UiQualifiedId *qmlTypeName, const Document *doc, Engine *engine);
virtual ~QmlPrototypeReference();
AST::UiQualifiedId *qmlTypeName() const;
virtual const Value *value(Context *context) const;
private:
AST::UiQualifiedId *_qmlTypeName;
const Document *_doc;
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
class QMLJS_EXPORT ASTVariableReference: public Reference
{
AST::VariableDeclaration *_ast;
public:
ASTVariableReference(AST::VariableDeclaration *ast, Engine *engine);
virtual ~ASTVariableReference();
virtual const Value *value(Context *context) const;
};
class QMLJS_EXPORT ASTFunctionValue: public FunctionValue
{
AST::FunctionDeclaration *_ast;
QList<NameId *> _argumentNames;
public:
ASTFunctionValue(AST::FunctionDeclaration *ast, Engine *engine);
virtual ~ASTFunctionValue();
AST::FunctionDeclaration *ast() const;
virtual const Value *returnValue() const;
virtual int argumentCount() const;
virtual const Value *argument(int) const;
virtual QString argumentName(int index) const;
virtual bool isVariadic() const;
};
class QMLJS_EXPORT ASTPropertyReference: public Reference
{
AST::UiPublicMember *_ast;
const Document *_doc;
QString _onChangedSlotName;
public:
ASTPropertyReference(AST::UiPublicMember *ast, const Document *doc, Engine *engine);
virtual ~ASTPropertyReference();
AST::UiPublicMember *ast() const { return _ast; }
QString onChangedSlotName() const { return _onChangedSlotName; }
virtual bool getSourceLocation(QString *fileName, int *line, int *column) const;
virtual const Value *value(Context *context) const;
};
class QMLJS_EXPORT ASTSignalReference: public Reference
{
AST::UiPublicMember *_ast;
const Document *_doc;
QString _slotName;
public:
ASTSignalReference(AST::UiPublicMember *ast, const Document *doc, Engine *engine);
virtual ~ASTSignalReference();
AST::UiPublicMember *ast() const { return _ast; }
QString slotName() const { return _slotName; }
virtual bool getSourceLocation(QString *fileName, int *line, int *column) const;
virtual const Value *value(Context *context) const;
};
class QMLJS_EXPORT ASTObjectValue: public ObjectValue
{
AST::UiQualifiedId *_typeName;
AST::UiObjectInitializer *_initializer;
const Document *_doc;
QList<ASTPropertyReference *> _properties;
QList<ASTSignalReference *> _signals;
public:
ASTObjectValue(AST::UiQualifiedId *typeName,
AST::UiObjectInitializer *initializer,
const Document *doc,
Engine *engine);
virtual ~ASTObjectValue();
bool getSourceLocation(QString *fileName, int *line, int *column) const;
virtual void processMembers(MemberProcessor *processor) const;
};
} } // end of namespace QmlJS::Interpreter
#endif // QMLJS_INTERPRETER_H