#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(node); if (! qmlObject) qmlObject = cast(node); if (qmlObject) setQmlScopeObject(qmlObject); // JS scopes if (FunctionDeclaration *fun = cast(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(toRemove)) _context->scopeChain().jsScopes.removeLast(); // QML scope object if (! _nodes.isEmpty() && (cast(toRemove) || cast(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(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(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(node)) initializer = definition->initializer; if (UiObjectBinding *binding = cast(node)) initializer = binding->initializer; if (initializer) { for (UiObjectMemberList *m = initializer->members; m; m = m->next) { if (UiScriptBinding *scriptBinding = cast(m->member)) { if (scriptBinding->qualifiedId && scriptBinding->qualifiedId->name->asString() == QLatin1String("target") && ! scriptBinding->qualifiedId->next) { // ### make Evaluate understand statements. if (ExpressionStatement *expStmt = cast(scriptBinding->statement)) { Evaluate evaluator(_context); const Value *targetValue = evaluator(expStmt->expression); if (const ObjectValue *target = value_cast(targetValue)) { scopeChain.qmlScopeObjects.prepend(target); } else { scopeChain.qmlScopeObjects.clear(); } } } } } } } #endif }