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