Some initial support for relative imports.

This commit is contained in:
Roberto Raggi
2010-01-26 17:23:18 +01:00
parent 5107ba57c2
commit 9cdca3a92b
6 changed files with 87 additions and 186 deletions

View File

@@ -30,6 +30,7 @@
#include "parser/qmljsast_p.h"
#include "qmljsbind.h"
#include "qmljsmetatypesystem.h"
#include <QtCore/QDebug>
using namespace QmlJS;
using namespace QmlJS::AST;
@@ -125,7 +126,10 @@ static QString serialize(UiQualifiedId *qualifiedId, QChar delimiter)
*/
bool Bind::visit(UiImport *ast)
{
ObjectValue *namespaceObject;
if (! (ast->importUri || ast->fileName))
return false; // nothing to do.
ObjectValue *namespaceObject = 0;
if (ast->asToken.isValid()) { // with namespace we insert an object in the type env. to hold the imported types
if (!ast->importId)
@@ -142,32 +146,57 @@ bool Bind::visit(UiImport *ast)
// look at files first
// else try the metaobject system
if (!ast->importUri)
return false;
if (ast->importUri) {
const QString package = serialize(ast->importUri, '/');
int majorVersion = -1; // ### TODO: Check these magic version numbers
int minorVersion = -1; // ### TODO: Check these magic version numbers
const QString package = serialize(ast->importUri, '/');
int majorVersion = -1; // ### TODO: Check these magic version numbers
int minorVersion = -1; // ### TODO: Check these magic version numbers
if (ast->versionToken.isValid()) {
const QString versionString = _doc->source().mid(ast->versionToken.offset, ast->versionToken.length);
const int dotIdx = versionString.indexOf(QLatin1Char('.'));
if (dotIdx == -1) {
// only major (which is probably invalid, but let's handle it anyway)
majorVersion = versionString.toInt();
minorVersion = 0; // ### TODO: Check with magic version numbers above
} else {
majorVersion = versionString.left(dotIdx).toInt();
minorVersion = versionString.mid(dotIdx + 1).toInt();
}
}
#ifndef NO_DECLARATIVE_BACKEND
foreach (QmlObjectValue *object, _interp->metaTypeSystem().staticTypesForImport(package, majorVersion, minorVersion)) {
namespaceObject->setProperty(object->qmlTypeName(), object);
}
#endif // NO_DECLARATIVE_BACKEND
} else if (ast->fileName) {
// got an import "contents"
const QString relativePath = ast->fileName->asString();
const QList<Document::Ptr> userComponents = _snapshot.importedDocuments(_doc, relativePath);
foreach (Document::Ptr userComponent, userComponents) {
if (UiProgram *program = userComponent->qmlProgram()) {
if (UiObjectMemberList *members = program->members) {
if (UiObjectDefinition *def = cast<UiObjectDefinition *>(members->member)) {
const ObjectValue *prototype = lookupType(def->qualifiedTypeNameId);
ObjectValue *objectValue = _interp->newObject(prototype);
if (def->initializer) {
for (AST::UiObjectMemberList *it = def->initializer->members; it; it = it->next) {
if (AST::UiPublicMember *prop = AST::cast<AST::UiPublicMember *>(it->member)) {
if (prop->name && prop->memberType) {
const QString propName = prop->name->asString();
const QString propType = prop->memberType->asString();
objectValue->setProperty(propName, _interp->defaultValueForBuiltinType(propType));
}
}
}
}
if (ast->versionToken.isValid()) {
const QString versionString = _doc->source().mid(ast->versionToken.offset, ast->versionToken.length);
const int dotIdx = versionString.indexOf(QLatin1Char('.'));
if (dotIdx == -1) {
// only major (which is probably invalid, but let's handle it anyway)
majorVersion = versionString.toInt();
minorVersion = 0; // ### TODO: Check with magic version numbers above
} else {
majorVersion = versionString.left(dotIdx).toInt();
minorVersion = versionString.mid(dotIdx + 1).toInt();
_typeEnvironment->setProperty(userComponent->componentName(), objectValue);
}
}
}
}
}
#ifndef NO_DECLARATIVE_BACKEND
foreach (QmlObjectValue *object, _interp->metaTypeSystem().staticTypesForImport(package, majorVersion, minorVersion)) {
namespaceObject->setProperty(object->qmlTypeName(), object);
}
#endif // NO_DECLARATIVE_BACKEND
return false;
}
@@ -199,15 +228,15 @@ const ObjectValue *Bind::lookupType(UiQualifiedId *qualifiedTypeNameId)
{
const ObjectValue *objectValue = _typeEnvironment;
for (UiQualifiedId *iter = qualifiedTypeNameId; iter; iter = iter->next) {
if (! (iter->name))
for (UiQualifiedId *iter = qualifiedTypeNameId; 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();
if (!objectValue)
return 0;
}
return objectValue;

View File

@@ -34,6 +34,7 @@
#include <qmljs/parser/qmljsparser_p.h>
#include <qmljs/parser/qmljsnodepool_p.h>
#include <qmljs/parser/qmljsastfwd_p.h>
#include <QtCore/QDir>
using namespace QmlJS;
using namespace QmlJS;
@@ -47,12 +48,14 @@ Document::Document(const QString &fileName)
, _parsedCorrectly(false)
, _fileName(fileName)
{
const int slashIdx = fileName.lastIndexOf('/');
if (slashIdx != -1)
_path = fileName.left(slashIdx);
if (fileName.toLower().endsWith(".qml"))
_componentName = fileName.mid(slashIdx + 1, fileName.size() - (slashIdx + 1) - 4);
QFileInfo fileInfo(fileName);
_path = fileInfo.absolutePath();
_componentName = fileInfo.baseName();
if (! _componentName.isEmpty()) {
// ### TODO: check the component name.
if (! _componentName.at(0).isUpper())
_componentName.clear();
}
}
Document::~Document()
@@ -220,7 +223,7 @@ Snapshot::~Snapshot()
void Snapshot::insert(const Document::Ptr &document)
{
if (document && (document->qmlProgram() || document->jsProgram()))
QMap<QString, Document::Ptr>::insert(document->fileName(), document);
_documents.insert(document->fileName(), document);
}
Document::PtrList Snapshot::importedDocuments(const Document::Ptr &doc, const QString &importPath) const
@@ -229,11 +232,16 @@ Document::PtrList Snapshot::importedDocuments(const Document::Ptr &doc, const QS
Document::PtrList result;
const QString docPath = doc->path() + '/' + importPath;
QString docPath = doc->path();
docPath += QLatin1Char('/');
docPath += importPath;
docPath = QDir::cleanPath(docPath);
foreach (Document::Ptr candidate, *this) {
foreach (Document::Ptr candidate, _documents) {
if (candidate == doc)
continue;
continue; // ignore this document
else if (! candidate->qmlProgram())
continue; // skip JS documents
if (candidate->path() == doc->path() || candidate->path() == docPath)
result.append(candidate);

View File

@@ -101,16 +101,25 @@ private:
QmlJS::Symbol::List _symbols;
};
class QMLJS_EXPORT Snapshot: public QMap<QString, Document::Ptr>
class QMLJS_EXPORT Snapshot
{
typedef QMap<QString, Document::Ptr> _Base;
QMap<QString, Document::Ptr> _documents;
public:
Snapshot();
~Snapshot();
typedef _Base::iterator iterator;
typedef _Base::const_iterator const_iterator;
const_iterator begin() const { return _documents.begin(); }
const_iterator end() const { return _documents.end(); }
void insert(const Document::Ptr &document);
Document::Ptr document(const QString &fileName) const
{ return value(fileName); }
{ return _documents.value(fileName); }
Document::PtrList importedDocuments(const Document::Ptr &doc, const QString &importPath) const;
QMap<QString, Document::Ptr> componentsDefinedByImportedDocuments(const Document::Ptr &doc, const QString &importPath) const;