diff options
author | Christian Kamm <christian.d.kamm@nokia.com> | 2010-02-19 15:55:11 +0100 |
---|---|---|
committer | Christian Kamm <christian.d.kamm@nokia.com> | 2010-02-22 10:22:23 +0100 |
commit | e9039db9847e76211fd7ad665d7b190b7d05ec9e (patch) | |
tree | 1d6a323a454f6a1a5e6d77163270007e55fd19ee /src/libs/qmljs/qmljsscopebuilder.cpp | |
parent | 08cfc8f28c1aaae1670fa96fc15e4abe00d72e18 (diff) | |
download | qt-creator-e9039db9847e76211fd7ad665d7b190b7d05ec9e.tar.gz |
Move the scope building logic into QmlJS::ScopeBuilder.
Diffstat (limited to 'src/libs/qmljs/qmljsscopebuilder.cpp')
-rw-r--r-- | src/libs/qmljs/qmljsscopebuilder.cpp | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/src/libs/qmljs/qmljsscopebuilder.cpp b/src/libs/qmljs/qmljsscopebuilder.cpp new file mode 100644 index 0000000000..4f3f6fa123 --- /dev/null +++ b/src/libs/qmljs/qmljsscopebuilder.cpp @@ -0,0 +1,129 @@ +#include "qmljsscopebuilder.h" + +#include "qmljsbind.h" +#include "qmljsinterpreter.h" +#include "qmljsevaluate.h" +#include "parser/qmljsast_p.h" + +using namespace QmlJS; +using namespace QmlJS::Interpreter; +using namespace QmlJS::AST; + +ScopeBuilder::ScopeBuilder(Document::Ptr doc, Interpreter::Context *context) + : _doc(doc) + , _context(context) +{ +} + +ScopeBuilder::~ScopeBuilder() +{ +} + +void ScopeBuilder::push(AST::Node *node) +{ + _nodes += node; + + // QML scope object + Node *qmlObject = cast<UiObjectDefinition *>(node); + if (! qmlObject) + qmlObject = cast<UiObjectBinding *>(node); + if (qmlObject) + setQmlScopeObject(qmlObject); + + // JS scopes + if (FunctionDeclaration *fun = cast<FunctionDeclaration *>(node)) { + ObjectValue *activation = _context->engine()->newObject(/*prototype = */ 0); + for (FormalParameterList *it = fun->formals; it; it = it->next) { + if (it->name) + activation->setProperty(it->name->asString(), _context->engine()->undefinedValue()); + } + _context->scopeChain().jsScopes += activation; + } + + _context->scopeChain().update(); +} + +void ScopeBuilder::pop() +{ + Node *toRemove = _nodes.last(); + _nodes.removeLast(); + + // JS scopes + if (cast<FunctionDeclaration *>(toRemove)) + _context->scopeChain().jsScopes.removeLast(); + + // QML scope object + if (! _nodes.isEmpty() + && (cast<UiObjectDefinition *>(toRemove) || cast<UiObjectBinding *>(toRemove))) + setQmlScopeObject(_nodes.last()); + + _context->scopeChain().update(); +} + +void ScopeBuilder::setQmlScopeObject(Node *node) +{ + ScopeChain &scopeChain = _context->scopeChain(); + + scopeChain.qmlScopeObjects.clear(); + + const ObjectValue *scopeObject = _doc->bind()->findQmlObject(node); + if (scopeObject) { + if (scopeObject != scopeChain.qmlComponentScope.rootObject) + scopeChain.qmlScopeObjects += scopeObject; + } + +#ifndef NO_DECLARATIVE_BACKEND + // check if the object has a Qt.ListElement ancestor + const ObjectValue *prototype = scopeObject->prototype(_context); + while (prototype) { + if (const QmlObjectValue *qmlMetaObject = dynamic_cast<const QmlObjectValue *>(prototype)) { + // ### Also check for Qt package. Involves changes in QmlObjectValue. + if (qmlMetaObject->qmlTypeName() == QLatin1String("ListElement")) { + scopeChain.qmlScopeObjects.clear(); + break; + } + } + prototype = prototype->prototype(_context); + } + + // check if the object has a Qt.PropertyChanges ancestor + prototype = scopeObject->prototype(_context); + while (prototype) { + if (const QmlObjectValue *qmlMetaObject = dynamic_cast<const QmlObjectValue *>(prototype)) { + // ### Also check for Qt package. Involves changes in QmlObjectValue. + if (qmlMetaObject->qmlTypeName() == QLatin1String("PropertyChanges")) + break; + } + prototype = prototype->prototype(_context); + } + // find the target script binding + if (prototype) { + UiObjectInitializer *initializer = 0; + if (UiObjectDefinition *definition = cast<UiObjectDefinition *>(node)) + initializer = definition->initializer; + if (UiObjectBinding *binding = cast<UiObjectBinding *>(node)) + initializer = binding->initializer; + if (initializer) { + for (UiObjectMemberList *m = initializer->members; m; m = m->next) { + if (UiScriptBinding *scriptBinding = cast<UiScriptBinding *>(m->member)) { + if (scriptBinding->qualifiedId + && scriptBinding->qualifiedId->name->asString() == QLatin1String("target") + && ! scriptBinding->qualifiedId->next) { + // ### make Evaluate understand statements. + if (ExpressionStatement *expStmt = cast<ExpressionStatement *>(scriptBinding->statement)) { + Evaluate evaluator(_context); + const Value *targetValue = evaluator(expStmt->expression); + + if (const ObjectValue *target = value_cast<const ObjectValue *>(targetValue)) { + scopeChain.qmlScopeObjects.prepend(target); + } else { + scopeChain.qmlScopeObjects.clear(); + } + } + } + } + } + } + } +#endif +} |