From ba18e7003421562b698d064998b8eecf1f92c4a1 Mon Sep 17 00:00:00 2001 From: Roberto Raggi <roberto.raggi@nokia.com> Date: Wed, 3 Feb 2010 10:24:25 +0100 Subject: [PATCH] Introduced QML/JS references. Done with ckamm --- src/libs/qmljs/qmljscheck.cpp | 13 ++++- src/libs/qmljs/qmljscheck.h | 4 +- src/libs/qmljs/qmljsinterpreter.cpp | 53 +++++++++++++++++++ src/libs/qmljs/qmljsinterpreter.h | 40 ++++++++++++++ src/libs/qmljs/qmljslink.cpp | 6 +++ src/libs/qmljs/qmljslink.h | 3 ++ src/plugins/qmljseditor/qmlcodecompletion.cpp | 2 +- src/plugins/qmljseditor/qmlhoverhandler.cpp | 2 +- 8 files changed, 119 insertions(+), 4 deletions(-) diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp index 2f59f7c0aa4..7532f48de37 100644 --- a/src/libs/qmljs/qmljscheck.cpp +++ b/src/libs/qmljs/qmljscheck.cpp @@ -36,8 +36,9 @@ using namespace QmlJS; using namespace QmlJS::Interpreter; -Check::Check(Interpreter::Engine *engine) +Check::Check(Interpreter::Engine *engine, Interpreter::Context *context) : _engine(engine), + _context(context), _scope(engine->globalObject()), _result(0) { @@ -57,11 +58,21 @@ const Interpreter::Value *Check::operator()(AST::Node *ast, const Interpreter::O const Interpreter::Value *Check::check(AST::Node *ast) { + // save the result const Value *previousResult = switchResult(0); + + // process the expression accept(ast); + + // restore the previous result const Value *result = switchResult(previousResult); + + if (const Reference *ref = value_cast<const Reference *>(result)) + result = ref->value(_context); + if (! result) result = _engine->undefinedValue(); + return result; } diff --git a/src/libs/qmljs/qmljscheck.h b/src/libs/qmljs/qmljscheck.h index f9a395cbe09..b37375ea7b1 100644 --- a/src/libs/qmljs/qmljscheck.h +++ b/src/libs/qmljs/qmljscheck.h @@ -37,6 +37,7 @@ namespace QmlJS { namespace Interpreter { class Engine; + class Context; class Value; class ObjectValue; class FunctionValue; @@ -45,7 +46,7 @@ namespace Interpreter { class QMLJS_EXPORT Check: protected AST::Visitor { public: - Check(Interpreter::Engine *engine); + Check(Interpreter::Engine *engine, Interpreter::Context *context); virtual ~Check(); const Interpreter::Value *operator()(AST::Node *ast, const Interpreter::ObjectValue *scope); @@ -155,6 +156,7 @@ protected: private: QmlJS::Document::Ptr _doc; Interpreter::Engine *_engine; + Interpreter::Context *_context; const Interpreter::ObjectValue *_scope; const Interpreter::Value *_result; }; diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp index 75e9258eb07..b248fd2f94d 100644 --- a/src/libs/qmljs/qmljsinterpreter.cpp +++ b/src/libs/qmljs/qmljsinterpreter.cpp @@ -567,6 +567,9 @@ void ValueVisitor::visit(const FunctionValue *) { } +void ValueVisitor::visit(const Reference *) +{ +} //////////////////////////////////////////////////////////////////////////////// // Value @@ -614,6 +617,11 @@ const FunctionValue *Value::asFunctionValue() const return 0; } +const Reference *Value::asReference() const +{ + return 0; +} + //////////////////////////////////////////////////////////////////////////////// // Environment //////////////////////////////////////////////////////////////////////////////// @@ -700,6 +708,51 @@ void StringValue::accept(ValueVisitor *visitor) const visitor->visit(this); } + +Context::Context(Engine *engine) + : _engine(engine) +{ +} + +Context::~Context() +{ +} + +Engine *Context::engine() const +{ + return _engine; +} + +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); +} + +Reference::Reference() +{ +} + +Reference::~Reference() +{ +} + +const Reference *Reference::asReference() const +{ + return this; +} + +void Reference::accept(ValueVisitor *visitor) const +{ + visitor->visit(this); +} + + MemberProcessor::MemberProcessor() { } diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h index ba4b7606560..623d56821c9 100644 --- a/src/libs/qmljs/qmljsinterpreter.h +++ b/src/libs/qmljs/qmljsinterpreter.h @@ -53,6 +53,7 @@ class BooleanValue; class StringValue; class ObjectValue; class FunctionValue; +class Reference; typedef QList<const Value *> ValueList; @@ -72,6 +73,7 @@ public: virtual void visit(const StringValue *); virtual void visit(const ObjectValue *); virtual void visit(const FunctionValue *); + virtual void visit(const Reference *); }; //////////////////////////////////////////////////////////////////////////////// @@ -93,6 +95,7 @@ public: virtual const StringValue *asStringValue() const; virtual const ObjectValue *asObjectValue() const; virtual const FunctionValue *asFunctionValue() const; + virtual const Reference *asReference() const; virtual void accept(ValueVisitor *) const = 0; }; @@ -141,6 +144,12 @@ template <> Q_INLINE_TEMPLATE const FunctionValue *value_cast(const Value *v) else return 0; } +template <> Q_INLINE_TEMPLATE const Reference *value_cast(const Value *v) +{ + if (v) return v->asReference(); + else return 0; +} + //////////////////////////////////////////////////////////////////////////////// // Execution environment //////////////////////////////////////////////////////////////////////////////// @@ -210,6 +219,37 @@ public: virtual bool processGeneratedSlot(const QString &name, const Value *value); }; +class QMLJS_EXPORT Context +{ +public: + Context(Engine *engine); + virtual ~Context(); + + Engine *engine() const; + + 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; +}; + +class QMLJS_EXPORT Reference: public Value +{ +public: + Reference(); + virtual ~Reference(); + + virtual const Value *value(const Context *context) const = 0; + + // Value interface + virtual const Reference *asReference() const; + virtual void accept(ValueVisitor *) const; +}; + class QMLJS_EXPORT ObjectValue: public Value, public Environment { public: diff --git a/src/libs/qmljs/qmljslink.cpp b/src/libs/qmljs/qmljslink.cpp index 9bcefb52649..55871970563 100644 --- a/src/libs/qmljs/qmljslink.cpp +++ b/src/libs/qmljs/qmljslink.cpp @@ -15,6 +15,7 @@ using namespace QmlJS::AST; Link::Link(Document::Ptr currentDoc, const Snapshot &snapshot, Interpreter::Engine *interp) : _snapshot(snapshot) , _interp(interp) + , _context(interp) { _docs = reachableDocuments(currentDoc, snapshot); @@ -47,6 +48,11 @@ static ObjectValue *pushScope(ObjectValue *next, ObjectValue *onto) return next; } +Context *Link::context() +{ + return &_context; +} + ObjectValue *Link::scopeChainAt(Document::Ptr doc, Node *currentObject) { BindPtr bind = doc->bind(); diff --git a/src/libs/qmljs/qmljslink.h b/src/libs/qmljs/qmljslink.h index 33be4736d10..1233412848f 100644 --- a/src/libs/qmljs/qmljslink.h +++ b/src/libs/qmljs/qmljslink.h @@ -23,6 +23,8 @@ public: Link(Document::Ptr doc, const Snapshot &snapshot, Interpreter::Engine *interp); ~Link(); + Interpreter::Context *context(); + // Get the scope chain for the currentObject inside doc. Interpreter::ObjectValue *scopeChainAt(Document::Ptr doc, AST::Node *currentObject); @@ -43,6 +45,7 @@ private: private: Snapshot _snapshot; Interpreter::Engine *_interp; + Interpreter::Context _context; QList<Document::Ptr> _docs; QHash<Document *, Interpreter::ObjectValue *> _typeEnvironments; }; diff --git a/src/plugins/qmljseditor/qmlcodecompletion.cpp b/src/plugins/qmljseditor/qmlcodecompletion.cpp index 097b6591897..75e7eca331d 100644 --- a/src/plugins/qmljseditor/qmlcodecompletion.cpp +++ b/src/plugins/qmljseditor/qmlcodecompletion.cpp @@ -670,7 +670,7 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) //qDebug() << "expression:" << expression; if (expression != 0) { - Check evaluate(&interp); + Check evaluate(&interp, link.context()); // Evaluate the expression under cursor. const Interpreter::Value *value = interp.convertToObject(evaluate(expression , scope)); diff --git a/src/plugins/qmljseditor/qmlhoverhandler.cpp b/src/plugins/qmljseditor/qmlhoverhandler.cpp index 979d8ea490e..2ee275643c6 100644 --- a/src/plugins/qmljseditor/qmlhoverhandler.cpp +++ b/src/plugins/qmljseditor/qmlhoverhandler.cpp @@ -175,7 +175,7 @@ void QmlHoverHandler::updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, in Link link(qmlDocument, snapshot, &interp); const Interpreter::ObjectValue *scope = link.scopeChainAt(qmlDocument, declaringMember); - Check check(&interp); + Check check(&interp, link.context()); const Interpreter::Value *value = check(node, scope); QStringList baseClasses; -- GitLab