2010-01-28 14:53:53 +01:00
|
|
|
#include "qmljslink.h"
|
|
|
|
|
|
|
|
#include "parser/qmljsast_p.h"
|
|
|
|
#include "qmljsdocument.h"
|
|
|
|
#include "qmljsbind.h"
|
|
|
|
|
|
|
|
#include <QtCore/QFileInfo>
|
|
|
|
#include <QtCore/QDir>
|
|
|
|
#include <QtCore/QDebug>
|
|
|
|
|
|
|
|
using namespace QmlJS;
|
|
|
|
using namespace QmlJS::Interpreter;
|
|
|
|
using namespace QmlJS::AST;
|
|
|
|
|
|
|
|
static QString componentName(const QString &fileName)
|
|
|
|
{
|
|
|
|
QString componentName = fileName;
|
|
|
|
int dotIndex = componentName.indexOf(QLatin1Char('.'));
|
|
|
|
if (dotIndex != -1)
|
|
|
|
componentName.truncate(dotIndex);
|
|
|
|
componentName[0] = componentName[0].toUpper();
|
|
|
|
return componentName;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LinkImports::linkImports(Bind *bind, const QList<Bind *> &binds)
|
|
|
|
{
|
|
|
|
// ### TODO: remove all properties from _typeEnv
|
|
|
|
|
|
|
|
Document::Ptr doc = bind->_doc;
|
|
|
|
if (! (doc->qmlProgram() && doc->qmlProgram()->imports))
|
|
|
|
return;
|
|
|
|
|
|
|
|
QFileInfo fileInfo(doc->fileName());
|
|
|
|
const QString absolutePath = fileInfo.absolutePath();
|
|
|
|
|
2010-01-29 13:21:50 +01:00
|
|
|
// implicit imports:
|
|
|
|
// qml files in the same directory are available without explicit imports
|
2010-01-28 14:53:53 +01:00
|
|
|
foreach (Bind *otherBind, binds) {
|
|
|
|
if (otherBind == bind)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Document::Ptr otherDoc = otherBind->_doc;
|
|
|
|
QFileInfo otherFileInfo(otherDoc->fileName());
|
|
|
|
const QString otherAbsolutePath = otherFileInfo.absolutePath();
|
|
|
|
|
|
|
|
if (otherAbsolutePath != absolutePath)
|
|
|
|
continue;
|
|
|
|
|
2010-01-29 13:21:50 +01:00
|
|
|
bind->_typeEnvironment->setProperty(componentName(otherFileInfo.fileName()),
|
|
|
|
otherBind->_rootObjectValue);
|
2010-01-28 14:53:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// explicit imports, whether directories or files
|
|
|
|
for (UiImportList *it = doc->qmlProgram()->imports; it; it = it->next) {
|
|
|
|
if (! (it->import && it->import->fileName))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
QString path = absolutePath;
|
|
|
|
path += QLatin1Char('/');
|
|
|
|
path += it->import->fileName->asString();
|
|
|
|
path = QDir::cleanPath(path);
|
|
|
|
|
2010-01-29 13:36:07 +01:00
|
|
|
ObjectValue *importNamespace = 0;
|
|
|
|
|
2010-01-28 14:53:53 +01:00
|
|
|
foreach (Bind *otherBind, binds) {
|
|
|
|
Document::Ptr otherDoc = otherBind->_doc;
|
|
|
|
QFileInfo otherFileInfo(otherDoc->fileName());
|
|
|
|
const QString otherAbsolutePath = otherFileInfo.absolutePath();
|
|
|
|
|
|
|
|
bool directoryImport = (path == otherAbsolutePath);
|
|
|
|
bool fileImport = (path == otherDoc->fileName());
|
|
|
|
if (!directoryImport && !fileImport)
|
|
|
|
continue;
|
|
|
|
|
2010-01-29 13:36:07 +01:00
|
|
|
if (directoryImport && it->import->importId && !importNamespace) {
|
|
|
|
importNamespace = bind->_interp->newObject(/*prototype =*/0);
|
|
|
|
bind->_typeEnvironment->setProperty(it->import->importId->asString(), importNamespace);
|
2010-01-28 14:53:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
QString targetName;
|
|
|
|
if (fileImport && it->import->importId) {
|
|
|
|
targetName = it->import->importId->asString();
|
|
|
|
} else {
|
|
|
|
targetName = componentName(otherFileInfo.fileName());
|
|
|
|
}
|
|
|
|
|
2010-01-29 13:36:07 +01:00
|
|
|
ObjectValue *importInto = bind->_typeEnvironment;
|
|
|
|
if (importNamespace)
|
|
|
|
importInto = importNamespace;
|
|
|
|
|
2010-01-28 14:53:53 +01:00
|
|
|
importInto->setProperty(targetName, otherBind->_rootObjectValue);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const ObjectValue *lookupType(ObjectValue *env, UiQualifiedId *id)
|
|
|
|
{
|
|
|
|
const ObjectValue *objectValue = env;
|
|
|
|
|
|
|
|
for (UiQualifiedId *iter = id; objectValue && iter; iter = iter->next) {
|
|
|
|
if (! iter->name)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
const Value *value = objectValue->property(iter->name->asString());
|
|
|
|
if (!value)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
objectValue = value->asObjectValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
return objectValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LinkImports::operator()(const QList<Bind *> &binds)
|
|
|
|
{
|
|
|
|
foreach (Bind *bind, binds) {
|
|
|
|
// Populate the _typeEnvironment with imports.
|
|
|
|
linkImports(bind, binds);
|
|
|
|
|
|
|
|
// Set the prototypes.
|
|
|
|
{
|
|
|
|
QHash<UiObjectDefinition *, ObjectValue *>::iterator it = bind->_qmlObjectDefinitions.begin();
|
|
|
|
QHash<UiObjectDefinition *, ObjectValue *>::iterator end = bind->_qmlObjectDefinitions.end();
|
|
|
|
for (; it != end; ++it) {
|
|
|
|
UiObjectDefinition *key = it.key();
|
|
|
|
ObjectValue *value = it.value();
|
|
|
|
if (!key->qualifiedTypeNameId)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
value->setPrototype(lookupType(bind->_typeEnvironment, key->qualifiedTypeNameId));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
|
|
|
QHash<UiObjectBinding *, ObjectValue *>::iterator it = bind->_qmlObjectBindings.begin();
|
|
|
|
QHash<UiObjectBinding *, ObjectValue *>::iterator end = bind->_qmlObjectBindings.end();
|
|
|
|
for (; it != end; ++it) {
|
|
|
|
UiObjectBinding *key = it.key();
|
|
|
|
ObjectValue *value = it.value();
|
|
|
|
if (!key->qualifiedTypeNameId)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
value->setPrototype(lookupType(bind->_typeEnvironment, key->qualifiedTypeNameId));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ObjectValue *Link::operator()(const QList<Bind *> &binds, Bind *currentBind, UiObjectMember *currentObject)
|
|
|
|
{
|
2010-02-01 17:04:31 +01:00
|
|
|
Q_UNUSED(binds);
|
2010-01-28 14:53:53 +01:00
|
|
|
ObjectValue *scopeObject;
|
|
|
|
if (UiObjectDefinition *definition = cast<UiObjectDefinition *>(currentObject))
|
|
|
|
scopeObject = currentBind->_qmlObjectDefinitions.value(definition);
|
|
|
|
else if (UiObjectBinding *binding = cast<UiObjectBinding *>(currentObject))
|
|
|
|
scopeObject = currentBind->_qmlObjectBindings.value(binding);
|
|
|
|
else
|
2010-01-28 15:03:12 +01:00
|
|
|
return currentBind->_interp->globalObject();
|
2010-01-28 14:53:53 +01:00
|
|
|
|
|
|
|
if (!scopeObject)
|
2010-01-28 15:03:12 +01:00
|
|
|
return currentBind->_interp->globalObject();
|
2010-01-28 14:53:53 +01:00
|
|
|
|
|
|
|
// Build the scope chain.
|
|
|
|
currentBind->_typeEnvironment->setScope(currentBind->_idEnvironment);
|
|
|
|
currentBind->_idEnvironment->setScope(currentBind->_functionEnvironment);
|
|
|
|
currentBind->_functionEnvironment->setScope(scopeObject);
|
|
|
|
if (scopeObject != currentBind->_rootObjectValue) {
|
|
|
|
scopeObject->setScope(currentBind->_rootObjectValue);
|
|
|
|
currentBind->_rootObjectValue->setScope(currentBind->_interp->globalObject());
|
|
|
|
} else {
|
|
|
|
scopeObject->setScope(currentBind->_interp->globalObject());
|
|
|
|
}
|
|
|
|
// May want to link to instantiating components from here.
|
|
|
|
|
|
|
|
return currentBind->_typeEnvironment;
|
|
|
|
}
|