forked from qt-creator/qt-creator
Get rid of Environment, introduce external ScopeChain in Link.
Done-with: Roberto
This commit is contained in:
@@ -29,6 +29,7 @@
|
||||
|
||||
#include "qmljscheck.h"
|
||||
#include "qmljsinterpreter.h"
|
||||
#include "qmljslink.h"
|
||||
#include "parser/qmljsparser_p.h"
|
||||
#include "parser/qmljsast_p.h"
|
||||
#include <QtCore/QDebug>
|
||||
@@ -36,10 +37,10 @@
|
||||
using namespace QmlJS;
|
||||
using namespace QmlJS::Interpreter;
|
||||
|
||||
Check::Check(Interpreter::Engine *engine, Interpreter::Context *context)
|
||||
: _engine(engine),
|
||||
_context(context),
|
||||
_scope(engine->globalObject()),
|
||||
Check::Check(Link *link)
|
||||
: _engine(link->engine()),
|
||||
_link(link),
|
||||
_scope(_engine->globalObject()),
|
||||
_result(0)
|
||||
{
|
||||
}
|
||||
@@ -48,12 +49,9 @@ Check::~Check()
|
||||
{
|
||||
}
|
||||
|
||||
const Interpreter::Value *Check::operator()(AST::Node *ast, const Interpreter::ObjectValue *scope)
|
||||
const Interpreter::Value *Check::operator()(AST::Node *ast)
|
||||
{
|
||||
const Interpreter::ObjectValue *previousScope = switchScope(scope);
|
||||
const Interpreter::Value *result = check(ast);
|
||||
(void) switchScope(previousScope);
|
||||
return result;
|
||||
return check(ast);
|
||||
}
|
||||
|
||||
const Interpreter::Value *Check::check(AST::Node *ast)
|
||||
@@ -68,7 +66,7 @@ const Interpreter::Value *Check::check(AST::Node *ast)
|
||||
const Value *result = switchResult(previousResult);
|
||||
|
||||
if (const Reference *ref = value_cast<const Reference *>(result))
|
||||
result = ref->value(_context);
|
||||
result = ref->value(_link->context());
|
||||
|
||||
if (! result)
|
||||
result = _engine->undefinedValue();
|
||||
@@ -167,7 +165,7 @@ bool Check::visit(AST::UiQualifiedId *ast)
|
||||
if (! ast->name)
|
||||
return false;
|
||||
|
||||
const Value *value = _scope->lookup(ast->name->asString());
|
||||
const Value *value = _link->lookup(ast->name->asString());
|
||||
if (! ast->next) {
|
||||
_result = value;
|
||||
|
||||
@@ -215,7 +213,7 @@ bool Check::visit(AST::IdentifierExpression *ast)
|
||||
if (! ast->name)
|
||||
return false;
|
||||
|
||||
_result = _scope->lookup(ast->name->asString());
|
||||
_result = _link->lookup(ast->name->asString());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
|
||||
namespace QmlJS {
|
||||
|
||||
class Link;
|
||||
|
||||
namespace Interpreter {
|
||||
class Engine;
|
||||
class Context;
|
||||
@@ -46,10 +48,10 @@ namespace Interpreter {
|
||||
class QMLJS_EXPORT Check: protected AST::Visitor
|
||||
{
|
||||
public:
|
||||
Check(Interpreter::Engine *engine, Interpreter::Context *context);
|
||||
Check(Link *link);
|
||||
virtual ~Check();
|
||||
|
||||
const Interpreter::Value *operator()(AST::Node *ast, const Interpreter::ObjectValue *scope);
|
||||
const Interpreter::Value *operator()(AST::Node *ast);
|
||||
|
||||
protected:
|
||||
void accept(AST::Node *node);
|
||||
@@ -156,7 +158,7 @@ protected:
|
||||
private:
|
||||
QmlJS::Document::Ptr _doc;
|
||||
Interpreter::Engine *_engine;
|
||||
Interpreter::Context *_context;
|
||||
Link *_link;
|
||||
const Interpreter::ObjectValue *_scope;
|
||||
const Interpreter::Value *_result;
|
||||
};
|
||||
|
||||
@@ -622,39 +622,6 @@ const Reference *Value::asReference() const
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Environment
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Environment::Environment()
|
||||
{
|
||||
}
|
||||
|
||||
Environment::~Environment()
|
||||
{
|
||||
}
|
||||
|
||||
const Environment *Environment::parent() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Value *Environment::lookup(const QString &name) const
|
||||
{
|
||||
if (const Value *member = lookupMember(name))
|
||||
return member;
|
||||
|
||||
else if (const Environment *p = parent())
|
||||
return p->lookup(name);
|
||||
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Value *Environment::lookupMember(const QString &) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Values
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -788,8 +755,7 @@ bool MemberProcessor::processGeneratedSlot(const QString &, const Value *)
|
||||
|
||||
ObjectValue::ObjectValue(Engine *engine)
|
||||
: _engine(engine),
|
||||
_prototype(0),
|
||||
_scope(0)
|
||||
_prototype(0)
|
||||
{
|
||||
engine->registerObject(this);
|
||||
}
|
||||
@@ -818,16 +784,6 @@ const ObjectValue *ObjectValue::prototype() const
|
||||
return _prototype;
|
||||
}
|
||||
|
||||
const ObjectValue *ObjectValue::scope() const
|
||||
{
|
||||
return _scope;
|
||||
}
|
||||
|
||||
void ObjectValue::setScope(const ObjectValue *scope)
|
||||
{
|
||||
_scope = scope;
|
||||
}
|
||||
|
||||
void ObjectValue::setProperty(const QString &name, const Value *value)
|
||||
{
|
||||
_members[name] = value;
|
||||
@@ -893,11 +849,6 @@ void ObjectValue::processMembers(MemberProcessor *processor) const
|
||||
}
|
||||
}
|
||||
|
||||
const Environment *ObjectValue::parent() const
|
||||
{
|
||||
return _scope;
|
||||
}
|
||||
|
||||
const Value *ObjectValue::lookupMember(const QString &name) const
|
||||
{
|
||||
if (const Value *m = _members.value(name))
|
||||
|
||||
@@ -150,20 +150,6 @@ template <> Q_INLINE_TEMPLATE const Reference *value_cast(const Value *v)
|
||||
else return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Execution environment
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
class QMLJS_EXPORT Environment
|
||||
{
|
||||
public:
|
||||
Environment();
|
||||
virtual ~Environment();
|
||||
|
||||
virtual const Environment *parent() const;
|
||||
virtual const Value *lookup(const QString &name) const;
|
||||
virtual const Value *lookupMember(const QString &name) const;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Value nodes
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -250,7 +236,7 @@ public:
|
||||
virtual void accept(ValueVisitor *) const;
|
||||
};
|
||||
|
||||
class QMLJS_EXPORT ObjectValue: public Value, public Environment
|
||||
class QMLJS_EXPORT ObjectValue: public Value
|
||||
{
|
||||
public:
|
||||
ObjectValue(Engine *engine);
|
||||
@@ -264,17 +250,12 @@ public:
|
||||
const ObjectValue *prototype() const;
|
||||
void setPrototype(const ObjectValue *prototype);
|
||||
|
||||
const ObjectValue *scope() const;
|
||||
void setScope(const ObjectValue *scope);
|
||||
|
||||
virtual void processMembers(MemberProcessor *processor) const;
|
||||
|
||||
virtual const Value *property(const QString &name) const;
|
||||
virtual void setProperty(const QString &name, const Value *value);
|
||||
virtual void removeProperty(const QString &name);
|
||||
|
||||
// Environment interface
|
||||
virtual const Environment *parent() const;
|
||||
virtual const Value *lookupMember(const QString &name) const;
|
||||
|
||||
// Value interface
|
||||
@@ -287,7 +268,6 @@ private:
|
||||
private:
|
||||
Engine *_engine;
|
||||
const ObjectValue *_prototype;
|
||||
const ObjectValue *_scope;
|
||||
QHash<QString, const Value *> _members;
|
||||
QString _className;
|
||||
};
|
||||
|
||||
@@ -24,69 +24,81 @@ Link::Link(Document::Ptr currentDoc, const Snapshot &snapshot, Interpreter::Engi
|
||||
|
||||
Link::~Link()
|
||||
{
|
||||
// unset all prototypes and scopes
|
||||
// unset all prototypes
|
||||
foreach (Document::Ptr doc, _docs) {
|
||||
BindPtr bind = doc->bind();
|
||||
|
||||
if (doc->qmlProgram()) {
|
||||
bind->_idEnvironment->setScope(0);
|
||||
bind->_functionEnvironment->setScope(0);
|
||||
|
||||
foreach (ObjectValue *object, bind->_qmlObjects) {
|
||||
object->setPrototype(0);
|
||||
object->setScope(0);
|
||||
}
|
||||
} else if (doc->jsProgram()) {
|
||||
bind->_rootObjectValue->setScope(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ObjectValue *pushScope(ObjectValue *next, ObjectValue *onto)
|
||||
{
|
||||
onto->setScope(next);
|
||||
return next;
|
||||
}
|
||||
|
||||
Context *Link::context()
|
||||
{
|
||||
return &_context;
|
||||
}
|
||||
|
||||
ObjectValue *Link::scopeChainAt(Document::Ptr doc, Node *currentObject)
|
||||
Link::ScopeChain Link::scopeChain() const
|
||||
{
|
||||
return _scopeChain;
|
||||
}
|
||||
|
||||
Interpreter::Engine *Link::engine()
|
||||
{
|
||||
return _interp;
|
||||
}
|
||||
|
||||
void Link::scopeChainAt(Document::Ptr doc, Node *currentObject)
|
||||
{
|
||||
_scopeChain.clear();
|
||||
|
||||
if (! doc) {
|
||||
_scopeChain.append(_interp->globalObject());
|
||||
return;
|
||||
}
|
||||
|
||||
BindPtr bind = doc->bind();
|
||||
|
||||
ObjectValue *scopeObject = 0;
|
||||
if (UiObjectDefinition *definition = cast<UiObjectDefinition *>(currentObject))
|
||||
scopeObject = bind->_qmlObjects.value(definition);
|
||||
|
||||
if (!scopeObject)
|
||||
return bind->_interp.globalObject();
|
||||
|
||||
// Build the scope chain.
|
||||
ObjectValue *scopeStart = _typeEnvironments.value(doc.data());
|
||||
ObjectValue *scope = scopeStart;
|
||||
scope = pushScope(bind->_idEnvironment, scope);
|
||||
scope = pushScope(bind->_functionEnvironment, scope);
|
||||
_scopeChain.append(_typeEnvironments.value(doc.data()));
|
||||
_scopeChain.append(bind->_idEnvironment);
|
||||
_scopeChain.append(bind->_functionEnvironment);
|
||||
|
||||
foreach (const QString &scriptFile, doc->bind()->includedScripts()) {
|
||||
if (Document::Ptr scriptDoc = _snapshot.document(scriptFile)) {
|
||||
if (scriptDoc->jsProgram()) {
|
||||
scope = pushScope(scriptDoc->bind()->_rootObjectValue, scope);
|
||||
_scopeChain.append(scriptDoc->bind()->_rootObjectValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scope = pushScope(scopeObject, scope);
|
||||
if (scopeObject != bind->_rootObjectValue)
|
||||
scope = pushScope(bind->_rootObjectValue, scope);
|
||||
|
||||
scope = pushScope(bind->_interp.globalObject(), scope);
|
||||
if (UiObjectDefinition *definition = cast<UiObjectDefinition *>(currentObject)) {
|
||||
ObjectValue *scopeObject = bind->_qmlObjects.value(definition);
|
||||
_scopeChain.append(scopeObject);
|
||||
|
||||
// ### FIXME: should add the root regardless
|
||||
if (scopeObject != bind->_rootObjectValue)
|
||||
_scopeChain.append(bind->_rootObjectValue);
|
||||
}
|
||||
|
||||
_scopeChain.append(bind->_interp.globalObject());
|
||||
|
||||
// May want to link to instantiating components from here.
|
||||
}
|
||||
|
||||
return scopeStart;
|
||||
const Value *Link::lookup(const QString &name) const
|
||||
{
|
||||
foreach (const ObjectValue *scope, _scopeChain) {
|
||||
if (const Value *member = scope->lookupMember(name)) {
|
||||
return member;
|
||||
}
|
||||
}
|
||||
|
||||
return _interp->undefinedValue();
|
||||
}
|
||||
|
||||
void Link::linkImports()
|
||||
|
||||
@@ -18,15 +18,22 @@ namespace QmlJS {
|
||||
*/
|
||||
class QMLJS_EXPORT Link
|
||||
{
|
||||
public:
|
||||
typedef QList<const Interpreter::ObjectValue *> ScopeChain;
|
||||
|
||||
public:
|
||||
// Link all documents in snapshot reachable from doc.
|
||||
Link(Document::Ptr doc, const Snapshot &snapshot, Interpreter::Engine *interp);
|
||||
~Link();
|
||||
|
||||
Interpreter::Context *context();
|
||||
ScopeChain scopeChain() const;
|
||||
Interpreter::Engine *engine();
|
||||
|
||||
// Get the scope chain for the currentObject inside doc.
|
||||
Interpreter::ObjectValue *scopeChainAt(Document::Ptr doc, AST::Node *currentObject);
|
||||
void scopeChainAt(Document::Ptr doc, AST::Node *currentObject);
|
||||
|
||||
const Interpreter::Value *lookup(const QString &name) const;
|
||||
|
||||
private:
|
||||
static QList<Document::Ptr> reachableDocuments(Document::Ptr startDoc, const Snapshot &snapshot);
|
||||
@@ -48,6 +55,7 @@ private:
|
||||
Interpreter::Context _context;
|
||||
QList<Document::Ptr> _docs;
|
||||
QHash<Document *, Interpreter::ObjectValue *> _typeEnvironments;
|
||||
ScopeChain _scopeChain;
|
||||
};
|
||||
|
||||
} // namespace QmlJS
|
||||
|
||||
Reference in New Issue
Block a user